Apache HTTP Server as Reverse Proxy

This section contains examples of how the Apache Web Server (version 2.2.20) can be used as a proxy in front of SignServer. The guide is only informative, please consult the current Apache documentation for the modules used.

The proxy can for example be used to:

  • Use standard ports (80, 443) instead of unprivileged ports used by the application server.

  • Make workers accessible through more nice looking URLs. For example, "http://tsa.example.com" instead of "http://example.com:8080/signserver/tsa?workerName=TimeStampSigner1".

  • Usie any of the access control and authentication mechanism available in Apache.

  • Redirect HTTP traffic to HTTPS.

  • Only accept requests to specified locations.

Since the requests should go through the proxy, it is recommended to configure the application server to only listen to localhost, and/or use a firewall blocking the application server ports from external requests. To configure JBoss to only listen to localhost, set the following properties in signserver_deploy.properties:

httpsserver.bindaddress.pubhttp=127.0.0.1
httpsserver.bindaddress.pubhttps=127.0.0.1
httpsserver.bindaddress.privhttps=127.0.0.1

Install the Apache web server and enable required modules (the following commands are for Ubuntu but should be similar in other distributions as well):

$ sudo apt-get install apache2
$ cd /etc/apache2/mods-enabled/
$ sudo ln -s ../mods-available/proxy.load proxy.load
$ sudo ln -s ../mods-available/proxy_http.load proxy_http.load
$ sudo ln -s ../mods-available/proxy_ajp.load proxy_ajp.load
$ sudo ln -s ../mods-available/proxy_balancer.load proxy_balancer.load
$ sudo ln -s ../mods-available/rewrite.load rewrite.load
$ sudo ln -s ../mods-available/ssl.load ssl.load

Example: Rewrite URLs for TSA (using mod_proxy and mod_rewrite)

The following sample configuration allows rendering nice URLs for time-stamping so that you can point your TSA clients to http://tsa.example.com/ instead of http://tsa.example.com:8080/signserver/process?workerName=TimeStampSigner1.

This configuration combines mod_proxy with mod_rewrite to enable setting the workerName or workerId, allowing different TSAs available on different URLs.

<VirtualHost tsa.example.com:80>
ServerName tsa.example.com
ServerAlias tsa.example.com
CustomLog /var/log/apache2/access.log combined
 
RewriteEngine on
RewriteLogLevel 5
RewriteLog "/var/log/apache2/rewrite.log
RewriteRule ^/$ /?workerName=TimeStampSigner1 [PT]
 
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://127.0.0.1:8080/signserver/process
ProxyPassReverse / http://127.0.0.1:8080/signserver/process
</VirtualHost>

Example: Rewrite URLs and redirect to HTTPS (using AJP)

The following example configures three virtual hosts.

The first signserver.example.com:80 redirects all requests to use HTTPS and thus the virtual host signserver.example.com:443.

The second virtual host is configured to proxy requests to the /signserver path on the application server using the AJP protocol. It is also configured to use HTTPS with a server certificate.

The last virtual hosts auth.signserver.example.com using an additional IP address is configured to require client certificate authentication.

Some application servers (for example, JBoss 4) might have problems writing the correct port number in the endpoint URL in the web services WSDL file when using a proxy (that is, writing 8443 instead of 443).

<VirtualHost signserver.example.com:80>
ServerName signserver.example.com
ServerAlias signserver.example.com
 
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
 
# Configure log
LogLevel warn
ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
 
</VirtualHost>
 
<VirtualHost signserver.example.com:443>
ServerName signserver.example.com
ServerAlias signserver.example.com
 
ProxyRequests Off
<Proxy balancer://mycluster-3>
BalancerMember ajp://localhost:8009/signserver
</Proxy>
ProxyPass / balancer://mycluster-3/
 
RewriteEngine On
 
# Treat requests to / and /signserver/ as the same for web services endpoints to work.
RewriteCond %{THE_REQUEST} /signserver/
RewriteRule ^/signserver/(.*)$ /$1 [PT]
 
# Configure secure SSL for this server using SSL certificate generated by EJBCA
SSLEngine on
SSLCipherSuite HIGH
SSLProtocol all -SSLv2
SSLCertificateFile /home/markus/Documents/PrimeKey/MarkusCA/example.com/signserver.example.com-cert.pem
SSLCertificateKeyFile /home/markus/Documents/PrimeKey/MarkusCA/example.com/signserver.example.com-key.pem
 
# Configure log
LogLevel warn
ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
</VirtualHost>
 
# Note: auth.signserver.example.com must have a different IP address
<VirtualHost auth.signserver.example.com:443>
ServerName auth.signserver.example.com
ServerAlias auth.signserver.example.com
 
ProxyRequests Off
<Proxy balancer://mycluster-4>
BalancerMember ajp://localhost:8009/signserver
</Proxy>
ProxyPass / balancer://mycluster-4/
 
RewriteEngine On
# Treat requests to / and /signserver/ as the same for web services endpoints to work.
RewriteCond %{THE_REQUEST} /signserver/
RewriteRule ^/signserver/(.*)$ /$1 [PT]
 
# Configure secure SSL for this server using SSL certificate generated by EJBCA
SSLEngine on
SSLCipherSuite HIGH
SSLProtocol all -SSLv2
SSLCertificateFile /home/markus/Documents/PrimeKey/MarkusCA/example.com/auth.signserver.example.com-cert.pem
SSLCertificateKeyFile /home/markus/Documents/PrimeKey/MarkusCA/example.com/auth.signserver.example.com-key.pem
 
SSLVerifyClient require
SSLVerifyDepth 1
SSLCACertificateFile /home/markus/Documents/PrimeKey/MarkusCA/example.com/truststore.pem
 
# Configure log
LogLevel warn
ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
</VirtualHost>

Example: Granting access to specific workers only

This example shows how to limit access to specified resources only.

If you are going to grant different users access to different workers, always remember to first deny access from the root location since there are other ways to access a worker than the "/worker/*" or "/sodworker/*" pattern. For instance, /process, /tsa, /pdf and /sod etc, as well as using the web services interfaces /signserverws, /SignServerWSService, /validationws, /ValidationWSService, and /ClientWSService, all can be used to invoke any worker.

If you instead relay on SignServer to do the authentication/authorization, it is recommended to only grant access to the locations you intend to use. In that case you will probably want to also give access to the web services interfaces, /worker and /process etc.

Also remember that if you are proxying from multiple virtual hosts (for example, if you have one with and one without client authentication as in the example above), you might want to add the access restrictions to all of them.

...
# First, deny access globally and then only give access to resources explicitly
<Location />
Order Deny,Allow
Deny from all
</Location>
 
# Allow index page
<LocationMatch "^/$">
Order Allow,Deny
Allow from all
</LocationMatch>
 
# Allow Client Web
<Location /clientweb/>
Order Allow,Deny
Allow from all
</Location>
 
# Allow documentation
<Location /doc/>
Order Allow,Deny
Allow from all
</Location>
 
# Allow web page resources
<LocationMatch "\.(css|js|jpg|png)$">
Order Allow,Deny
Allow from all
</LocationMatch>
# Allow the Admin interface
<Location /AdminWSService/>
Order Allow,Deny
Allow from all
</Location>
 
# Grant everybody access to the XMLSigner
<Location /worker/XMLSigner>
Order Allow,Deny
Allow from all
</Location>
# Grant everybody access to the MRTDSODSigner
<Location /sodworker/MRTDSODSigner>
Order Allow,Deny
Allow from all
</Location>
 
# Grant valid users access to the CMSSigner
<Location /worker/CMSSigner>
Order Allow,Deny
Allow from all
AuthType Basic
AuthName "Restricted CMSSigner access"
AuthUserFile /home/markus/.htpasswd
Require valid-user
</Location>
...

Additional Configuration

Custom Private HTTPS port

For example, if a reverse proxy is used to change the ports used by SignServer, the links in the Administration Web interface might not be correct (for example, if the standard port 443 is used instead of 8443). In that case, configure the following in conf/signserver_deploy.properties:

httpserver.external.privhttps=443

Custom Context Root

With a reverse proxy, it is also possible to use a different beginning of the URL for accessing SignServer than the default "/signserver". If for example the reverse proxy instead serves SignServer under "/myservice/signserver" this might have to be configured in conf/signserver_deploy.properties so that the URLs in the Administration Web interface, as well as the Web Services endpoints, work as expected:

httpserver.context.root=/myservice/signserver