Configuring Apache Web Server with JBoss

In a production environment, it is a best-practice to integrate a web server to handle static content. This reduces load on the application servers, which results in faster response times for users. For application security, many Appian installations also use SSL encryption at the web server layer or using a hardware SSL accelerator in front of the web server.

Due to the potential for negative impact on site performance applying SSL encryption/decryption at the application server level should be tested thoroughly before use in production.

The web server decides whether to handle a request or not based on the request URL's extension (or some other URL pattern). For instance, it is highly likely that we would want the web server to handle requests for JPG files (images), but not JSP files (dynamic pages). This is known as MIME-type filtering.

When the web server encounters a request that it can't handle itself, it passes the request to the application server, returning the application server response to the user. When a web server is configured in this manner, it is acting as a reverse-proxy. Apache and JBoss communicate using the AJP13 protocol.

Perform the steps below to configure an Apache HTTP 2.4 Server to selectively handle some requests and pass others to the application server. For this example, we use a JBoss application server on a Linux operating system, and assuming SSL configuration for Apache.

Pre-Requisites

It's impractical to list all of the various configurations between the operating system, web server, and application server. Instead, this guide was created with the following assumptions:

  1. A verified version of Apache 2.4 has been installed.
    • The root installation path of Apache will hereinafter referred to as <APACHE_HOME>
  2. mod_jk module (.so file), which can be found here: tomcat.apache.org has been moved into <APACHE_HOME>/modules.
    • Modules are libraries that can be plugged in Apache to offer extended functionality. The mod_jk module is used to configure Apache as a reverse-proxy for an application server.
    • Use modk_jk.1.2.x.so. For this example we loaded 1.2.42.
  3. Apache is using HTTPS, which requires a certificate to carry out its encryption routines.
    • It's assumed that the certificate has already been created and digitally signed by a commercial certification authority.
    • If you need to generate and self-sign a certificate for testing or training purposes, please follow the generating a certificate instructions before continuing to the next section.
    • The digitally-signed certificate and key (server.key) should be moved to <APACHE_HOME>/conf/
    • Default port, 443 for HTTPS is being used.
  4. No configurations have been made to Apache that prevents GET, POST, PUT, DELETE, HEAD, OPTIONS (only required for cross-origin requests), or CONNECT from being sent to the app server.
    • These settings are enabled by default and must remain enabled for the Appian software to function properly.

Deviations from these assumptions can still yield a valid web server setup, but additional configuration steps may be required. Finally, JBoss' root installation path will hereinafter referred to as <JBOSS_HOME>

Configure JBoss

  • To tell JBoss that it should be listening for requests from the web server, configure the connector subsystem and the corresponding socket binding in <JBOSS_HOME>/standalone/configuration/standalone.xml.
  • Verify that the following <connector> element is defined in the <subsystem xmlns="urn:jboss:domain:web:2.*"> element:
<connector name="ajp" protocol="AJP/1.3" scheme="http" socket-binding="ajp"/>
  • Add an instance-id attribute in the <subsystem xmls:"urn:jboss:domain:web:2.*"> element should be set to a value that uniquely identifies this JBoss instance. Add an instance-id attribute and set it to node1. This id will be used to identify this application server to Apache workers.
    • For environments running multiple application servers, each application server's standalone.xml file would need modified with a unique instance-id. For example, node2, node3, etc.
<subsystem xmlns="urn:jboss:domain:web:2.2" default-virtual-server="default-host" native="false" instance-id="node1">
  • Verify that the following <socket-binding> element is defined in the <socket-binding-group> element.
    • The port number specified is 8009. Apache must send requests to JBoss using the correct port number.
<socket-binding name="ajp" port="8009"/>

Configure httpd.conf

httpd.conf is the primary configuration file for Apache. All of the configurations steps below will be done by updating or adding settings to the httpd.conf file.

Load mod_JK Module

  1. In the httpd.conf file, update the pre-loaded modules with the mod_jk module:
    • The module file listed here corresponds to the 1.2.42 modules on Apache Web Server 2.4. Use the appropriate number suffix for different installation modules.
 LoadModule jk_module modules/mod_jk-1.2.42-httpd-2.4.x.so
 

Enable Other Modules

Apache comes with several modules pre-loaded that are either enabled or disabled by default. Ensure that your httpd.conf file has the follow modules enables, by removing the # symbol before the LoadModule line:

  • expires_module
  • headers_module

Setup Worker Properties

Specific worker properties are configured using the JKWorkerProperty directive. Workers will execute servlets on behalf of the web server.

  1. Add the following lines to the httpd.conf file:
JKWorkerProperty worker.list=LoadBalancer

JKWorkerProperty worker.node1.host=<APPLICATION SERVER IP ADDRESS>
JKWorkerProperty worker.node1.port=8009
JKWorkerProperty worker.node1.type=ajp13
JKWorkerProperty worker.node1.socket_connect_timeout=5000

JKWorkerProperty worker.LoadBalancer.type=lb
JKWorkerProperty worker.LoadBalancer.balance_workers=node1
JKWorkerProperty worker.LoadBalancer.sticky_session=1

Even though we're only connecting to a single app server, we're setting load balance properties now for ease of configuration later

Enable SSL

For application security, many installations opt to use encryption at the web server layer or using an SSL accelerator hardware device in front of the web server. Configuration settings for this option will vary, depending on your environment. This information is provided as an example of one possible configuration. The SSL module (mod_ssl) comes pre-installed with Apache 2.4.

Configure SSL Property Settings

  1. In httpd.conf, verify that the LoadModule directive: LoadModule ssl_module modules/mod_ssl.so is not commented out.
  2. Add the following SSL property settings to httpd.conf:
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
SSLSessionCache shmcb:/tmp/ssl_gcache_data(512000) 
SSLCertificateFile "<APACHE_HOME>/conf/<CERTFILENAME.crt>"
SSLCertificateKeyFile "<APACHE_HOME>/conf/<KEYFILENAME.key>"
SSLCertificateChainFile "<APACHE_HOME>/conf/<CERTFILENAME.crt>"

Allow httpd.conf to use SSL Information

  1. Add the following properties to httpd.conf to allow mod_jk to use the SSL information:
# Should mod_jk send SSL information to the application server (default is On)
JkExtractSSL On
# What is the indicator for SSL (default is HTTPS)
JkHTTPSIndicator HTTPS
# What is the indicator for SSL session (default is SSL_SESSION_ID)
JkSESSIONIndicator SSL_SESSION_ID
# What is the indicator for client SSL cipher suit (default is SSL_CIPHER)
JkCIPHERIndicator SSL_CIPHER
# What is the indicator for the client SSL certificated (default is SSL_CLIENT_CERT)
JkCERTSIndicator SSL_CLIENT_CERT
# Allow all vhost to inherit mounts from the main server (default is Off)
JkMountCopy All

Configure Apache to handle requests for static content

Apache will take of handling requests for static content like images and javascript.

  1. Add the following line to the httpd.conf file.
    • Note If the nosniff setting for the for the X-Content-Type-Options response header is user, omit SetEnvIf REQUEST_URI "\.gif$" no-jk
<VirtualHost *:443>
  ServerName yourhostname.yourdomain.com
  SSLEngine on
</VirtualHost>
           
DocumentRoot "<APACHE HOME>/www"

<Location /suite/>
  SetHandler jakarta-servlet
  SetEnv JK_WORKER_NAME LoadBalancer
  SetEnvIf REQUEST_URI "\.css$" no-jk
  SetEnvIf REQUEST_URI "\.jpg$" no-jk
  SetEnvIf REQUEST_URI "\.js$" no-jk
  SetEnvIf REQUEST_URI "\.html$" no-jk
  SetEnvIf REQUEST_URI "\.png$" no-jk
  SetEnvIf REQUEST_URI "\.xml$" no-jk
  SetEnvIf REQUEST_URI "\.ico$" no-jk
  SetEnvIf REQUEST_URI "\.xsl$" no-jk
  SetEnvIf REQUEST_URI "\.gwt\.rpc$" no-jk
  SetEnvIf REQUEST_URI "\.svg$" no-jk
  SetEnvIf REQUEST_URI "\.htc$" no-jk
  SetEnvIf REQUEST_URI "\.otf$" no-jk
  # If the nosniff setting for the X-Content-Type-Options response
  # header is used, omit the SetEnvIf line for .gif extenstions.
  SetEnvIf REQUEST_URI "\.gif$" no-jk

  SetEnvIf REQUEST_URI "/suite/s/" !no-jk
  SetEnvIf REQUEST_URI "/suite/plugins/servlet" !no-jk
</Location>

<Location /extras/>
  SetHandler jakarta-servlet
  SetEnv JK_WORKER_NAME LoadBalancer
</Location>


This configuration example does not use the JKMount directive to tell Apache explicitly what to pass on the application server. Instead, it lists only those extensions which the web server should handle with exceptions noted with !no-jk. Everything else will be passed on to the application server. This method of configuring mod_jk for Apache is simpler and will require fewer changes between upgrades.

Prevent jsessionid from Appearing in the URL

  1. To prevent jsessionid from appearing in a URL, add the following lines to httpd.conf:
JkStripSession On
<Directory "<APACHE_HOME>/www/suite">
  AllowOverride FileInfo
  Require all granted
</Directory>

Configuring Cache Settings for Appian Content

Add the following properties to httpd.conf (updating the Directory tag with your directory path as needed) to aggressively cache unchanging static content and to prevent certain dynamic paths from being cached:

<LocationMatch "/suite/JSON-RPC">
  Header set Cache-Control no-store
</LocationMatch>
<LocationMatch "/suite/doc">
  Header set Cache-Control no-store
</LocationMatch>
<LocationMatch "\.(?i:do|bg|popup)$">
  Header set Cache-Control no-store
</LocationMatch>

<Directory "<APACHE_HOME>">
  ExpiresActive On
  <FilesMatch "\.(css|jpg|gif|js|html|png|xml|ico|xsl|gwt\.rpc|eot|svg|tff|woff)$">
    ExpiresDefault "now plus 1 hour"
  </FilesMatch>
  <Files "*.cache.html">
    ExpiresDefault "now plus 1 day"
  </Files>
  <FilesMatch "\.cache\.(js|css|less)">
    ExpiresDefault "now plus 1 year"
  </FilesMatch>
  <Files "*.nocache.js">
    ExpiresDefault "now"
    Header set Cache-Control "max-age=0, must-revalidate"
  </Files>
</Directory>

Copy Static Resources to the Web Server

Since the web server will be handling requests for static resources and forwarding all other requests to the application server, you need to copy over the static files that ship with Appian.

  1. In <APACHE HOME> create a the following folder structure www/suite. This will be the home for static web content read by the web server.
  2. Copy all of the files from the <APPIAN_HOME>/ear/suite.ear/web.war directory to www/suite.

If the web server is on a separate machine than the application server, a common configuration, these files will need to be copied to that location on the other machine.

Configure SERVER_AND_PORT Properties in Appian

Once Apache has been enabled, all requests are sent directly to the web server. The SERVER_AND_PORT property must be configured to the value of the web server hostname and port.

  1. Open the custom.properties configuration file in the following location: <APPIAN_HOME>/ear/suite.ear/conf/.
  2. Ensure the SCHEME property is set to the following: conf.suite.SCHEME=https
  3. Ensure the SERVER_AND_PORT property is set to the following: conf.suite.SERVER_AND_PORT=<WEB_SERVER_HOST>

Verify Your Settings

Start (or restart) Apache and check that results in a web server that is listening on port 443, with HTTPS enabled.

Optional Configurations

Load Balancing Multiple Application Servers

In the configurations above, only one application server is being used. If you want to configure two or more application servers for failover and load balancing, add a definition corresponding to each application server ensuring that the AJP port is different for each server based on the following example:

JKWorkerProperty worker.list=LoadBalancer
#node1
JKWorkerProperty worker.node1.host=<APPLICATION SERVER 1 IP ADDRESS>
JKWorkerProperty worker.node1.port=8009
JKWorkerProperty worker.node1.type=ajp13
JKWorkerProperty worker.node1.socket_connect_timeout=5000
#node2
JKWorkerProperty worker.node2.host=<APPLICATION SERVER 2 IP ADDRESS>
JKWorkerProperty worker.node2.port=8009
JKWorkerProperty worker.node2.type=ajp13
JKWorkerProperty worker.node2.socket_connect_timeout=5000
#LoadBalancer worker
JKWorkerProperty worker.LoadBalancer.type=lb
JKWorkerProperty worker.LoadBalancer.balance_workers=node1,node2
JKWorkerProperty worker.LoadBalancer.sticky_session=1

The balanced_workers property now lists node1 and node2. Ensure that the ajp13 port number for each application server running matches the whats in that application server's standalone.xml file. This was verified previously in the configue JBoss section when checking the socket-binding element.

If the multiple application servers are running on the same machine, the port numbers will have to be adjusted appropriately.

Setup a Redirect

It is generally a good idea to redirect all the non-HTTPS traffic on port 80 through the HTTPS port. To do so, add the following lines to the httpd.conf file:

<VirtualHost *:80>
ServerAlias *
RewriteEngine on
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [L,R]
</VirtualHost>

Configure Timeout and KeepAlive

For improved performance, add (or change if already present) the following properties to the httpd.conf file:

Timeout 300
KeepAlive On
KeepAliveTimeout 60

Configure Compression Using the Deflate Module

One option for maximizing scalability is to compress the javascript, .CSS, and plain text files served by Appian, which reduces the bandwidth they consume. This is done using the Apache compression module, called the deflate module, or mod_deflate.so.

Append the following lines to the httpd.conf file, which enables the compression for all JS, CSS, HTML and plain text files:

 #Load compression module
 LoadModule deflate_module modules/mod_deflate.so
 #This filter indicates the MIME types to compress (javascript, css, plain text (used by the Process Modeler) and html.
 AddOutputFilterByType DEFLATE text/plain text/html text/javascript application/x-javascript application/javascript text/css text/xml application/json application/atom+json application/vnd.appian.tv.ui+json
 #Compression level 6 is the optimal setting.
 DeflateCompressionLevel 6

About Compression Levels

  • DeflateCompressionLevel specifies the level of compression used. The higher the value, the better the compression.
  • CPU usage also increases with each setting level.
  • In testing with Appian files, the average file-size reduction achieved when moving from level 1 to level 6, was 50 KB. The average compression achieved moving from level 6 to level 9, was an additional 1 KB. This is why compression level 6 is listed as the optimal setting.

To learn more about DeflateCompressionLevel, checkout the Apache documentation regarding mod_deflate

Generating a Certificate

If you need a certificate and key for HTTPs, follow these steps to generate on. These steps are using an OpenSSL package installed locally to generate a certificate. For enterprise installations, obtaining a digitally signed certification should be obtained through different means.

  1. From the command prompt, switch to the /bin directory in your OpenSSL directory.
  2. Create a private key for our server and (based on that key) create a certificate signing request (CSR).
  3. Set the path of the openssl.cnf file using: set OPENSSL_CONF=/path/to/openssl.cnf
  4. Type the following into the command prompt: <OPENSSL_INSTALL>\bin\conf>openssl req -config openssl.cnf -new -out server.csr.
  5. The OpenSSL program asks you a series of questions used to generate the certificate. When prompted for the Common Name to be used on the certificate, be sure to enter your domain name. Otherwise, browsers issue security warnings to your users.
    • This creates a private key (privkey.pem) and a signing request (server.csr).
  6. Create a key file that contains the server's private key without a passphrase: <OPENSSL_INSTALL>\bin\conf>openssl rsa -in privkey.pem -out server.key
  7. Sign the CSR that we created in the first step.
    • For this example, we create the certificate file ourselves named server.crt by entering the following command: <OPENSSL_INSTALL>\bin\conf>openssl x509 -in server.csr -out server.crt -req -signkey server.key -days 365.
  8. Move the certificate (server.crt) and key (server.key) key files can now be used by Apache.
FEEDBACK