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.
Tip: 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 Appian 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 Linux operating system and assuming SSL configuration for Apache.
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:
<APACHE_HOME>
mod_jk
module (.so file), which can be found here: tomcat.apache.org has been moved into <APACHE_HOME>/modules
.
mod_jk
module is used to configure Apache as a reverse-proxy for an application server.mod_jk.1.2.x.so
. For this example we loaded 1.2.42.server.key
) should be moved to <APACHE_HOME>/conf/
443
for HTTPS is being used.Deviations from these assumptions can still yield a valid web server setup, but additional configuration steps may be required.
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.
httpd.conf
file, update the pre-loaded modules with the mod_jk
module:
1
LoadModule jk_module modules/mod_jk-1.2.42-httpd-2.4.x.so
Apache comes with several modules pre-loaded that are either enabled or disabled by default. Ensure that your httpd.conf
file has the following modules enables, by removing the #
symbol before the LoadModule
line:
expires_module
headers_module
Specific worker properties are configured using the JKWorkerProperty
directive. Workers will execute servlets on behalf of the web server.
httpd.conf
file:1
2
3
4
5
6
7
8
9
10
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
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.
httpd.conf
, verify that the LoadModule directive: LoadModule ssl_module modules/mod_ssl.so
is not commented out.httpd.conf
:
1
2
3
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
SSLSessionCache shmcb:/tmp/ssl_gcache_data(512000)
httpd.conf
to allow mod_jk
to use the SSL information:
1
2
3
4
5
6
7
8
9
10
11
12
# 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
Apache uses virtual hosts to separate requests for the primary site URL, static content URL, and dynamic content URL. Each virtual host determines which requests should be handled by the web server and which requests should be passed through to the application server.
Note: 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.
This virtual host is used to serve the primary site URL. The ServerName directive should match the value used for conf.suite.SERVER_AND_PORT
in custom.properties
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<VirtualHost *:443>
ServerName yourhostname.yourdomain.com
SSLEngine on
SSLCertificateFile "<APACHE_HOME>/conf/<yourdomain.com.crt>"
SSLCertificateKeyFile "<APACHE_HOME>/conf/<yourdomain.com.key>"
SSLCertificateChainFile "<APACHE_HOME>/conf/<yourdomain.com.crt>"
DocumentRoot "<APACHE HOME>/www"
<Location /suite/>
SetHandler jakarta-servlet
SetEnv JK_WORKER_NAME LoadBalancer
SetEnvIf REQUEST_URI "\.css$" no-jk
SetEnvIf REQUEST_URI "\.eot$" 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
SetEnvIf REQUEST_URI "\.ttf$" no-jk
SetEnvIf REQUEST_URI "\.woff$" no-jk
SetEnvIf REQUEST_URI "\.woff2$" 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>
</VirtualHost>
This virtual host is used to serve the static content domain. The ServerName directive should match the value used for conf.suite.STATIC_SERVER_AND_PORT
in custom.properties
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<VirtualHost *:443>
ServerName yourhostname.yourdomain-static.com
SSLEngine on
SSLCertificateFile "<APACHE_HOME>/conf/<yourdomain-static.com.crt>"
SSLCertificateKeyFile "<APACHE_HOME>/conf/<yourdomain-static.com.key>"
SSLCertificateChainFile "<APACHE_HOME>/conf/<yourdomain-static.com.crt>"
DocumentRoot "<APACHE HOME>/www"
<Location /suite/rest/a/content/latest/docview/>
SetHandler jakarta-servlet
SetEnv JK_WORKER_NAME LoadBalancer
</Location>
</VirtualHost>
This virtual host is used to serve the dynamic content domain. The ServerName directive should match the value used for conf.suite.DYNAMIC_SERVER_AND_PORT
in custom.properties
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<VirtualHost *:443>
ServerName yourhostname.yourdomain-dynamic.com
SSLEngine on
SSLCertificateFile "<APACHE_HOME>/conf/<yourdomain-dynamic.com.crt>"
SSLCertificateKeyFile "<APACHE_HOME>/conf/<yourdomain-dynamic.com.key>"
SSLCertificateChainFile "<APACHE_HOME>/conf/<yourdomain-dynamic.com.crt>"
DocumentRoot "<APACHE HOME>/www"
<Location /suite/rest/a/content/latest/webcontent/>
SetHandler jakarta-servlet
SetEnv JK_WORKER_NAME LoadBalancer
</Location>
</VirtualHost>
httpd.conf
:1
2
3
4
5
6
7
8
9
10
11
12
13
JkStripSession On
<Directory "<APACHE_HOME>/www/suite">
AllowOverride FileInfo
Require all granted
</Directory>
<Directory "<APACHE_HOME>/www/suite/WEB-INF">
Require all denied
</Directory>
<Directory "<APACHE_HOME>/www/suite/dataload">
Require all denied
</Directory>
Add the following properties to httpd.conf
(updating the Directory tag with your directory path as needed) to aggressively cache unchanging web content and to prevent certain dynamic paths from being cached:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<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|htc|jpg|gif|js|html|png|xml|ico|xsl|gwt\.rpc|otf|eot|svg|tff|woff|woff2)$">
Header set Access-Control-Allow-Origin "*"
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>
Since the web server will be handling requests for web resources and forwarding all other requests to the application server, you need to copy over the files that ship with Appian.
<APACHE HOME>
create a the following folder structure www/suite
. This will be the home for content read by the web server.<APPIAN_HOME>/deployment/web.war
directory to www/suite
.Tip: 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.
Once Apache has been enabled, all requests are sent directly to the web server. The SERVER_AND_PORT
, STATIC_SERVER_AND_PORT
, and DYNAMIC_SERVER_AND_PORT
properties must be configured to point to the web server.
custom.properties
configuration file in the following location: <APPIAN_HOME>/conf/
.SCHEME
property is set to the following: conf.suite.SCHEME=https
SERVER_AND_PORT
property is set to the following: conf.suite.SERVER_AND_PORT=<WEB_SERVER_HOST>
STATIC_SERVER_AND_PORT
property is set to the following: conf.suite.STATIC_SERVER_AND_PORT=<WEB_SERVER_STATIC_HOST>
DYNAMIC_SERVER_AND_PORT
property is set to the following: conf.suite.DYNAMIC_SERVER_AND_PORT=<WEB_SERVER_DYNAMIC_HOST>
Note: Only include the port in the SERVER_AND_PORT parameter in your custom.properties file when not using the default HTTPS port (443). Specifying the default port may result in users receiving 401 errors. For more information, see Appian KB-1011.
See Post-Install Configurations for more details on configuring these properties.
Start (or restart) Apache and check that results in a web server that is listening on port 443
, with HTTPS enabled.
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 the same for each server based on the following example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
. When deploying Appian via the configure script, ensure that the names you use in the Configure Tomcat clustering by specifying a node name
step match the node names specified here.
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:
1
2
3
4
5
6
<VirtualHost *:80>
ServerAlias *
RewriteEngine on
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [L,R]
</VirtualHost>
One common scenario is when a firewall exists between the web server and the application server, inactive connections can get dropped. KeepAlive will tell the Operating System to send KEEP_ALIVE messages on inactive connections, preventing the firewall from severing inactive connections. For improved performance, add (or change if already present) the following properties to the httpd.conf
file:
1
2
3
Timeout 300
KeepAlive On
KeepAliveTimeout 60
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:
1
2
3
4
5
6
#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
DeflateCompressionLevel
specifies the level of compression used. The higher the value, the better the compression.To learn more about DeflateCompressionLevel, checkout the Apache documentation regarding mod_deflate
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.
/bin
directory in your OpenSSL directory.openssl.cnf
file using: set OPENSSL_CONF=/path/to/openssl.cnf
<OPENSSL_INSTALL>\bin\conf>openssl req -config openssl.cnf -new -out server.csr
.Common Name
to be used on the certificate, be sure to enter your domain name. Otherwise, browsers issue security warnings to your users.
privkey.pem
) and a signing request (server.csr
).<OPENSSL_INSTALL>\bin\conf>openssl rsa -in privkey.pem -out server.key
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
.server.crt
) and key (server.key
) key files can now be used by Apache.Configuring Apache Web Server with Appian