Installing as a Windows Service -WSO2 APIM 3.0.0 with JDK 11

Who has installed WSO2 products in the Windows environment, they would like to start the WSO2 servers as widows service. Today I am going to explain how to start the WSO2 APIM 3.0.0 as Windows Service by using a Java Service Wrapper library. For this, I have used windows 10 with JDK 11 versions.

Prerequisites

  1. Download APIM 3.0.0 from here
  2. You need to install JDK and set up the JAVA_HOME environment variable and you need to add that JAVA_HOME/bin to PATH variable as follows.
Image Rererence[1]

3. Download and install a service wrapper library to use for running the WSO2 API Manager as a Windows service. WSO2 recommends Yet Another Java Service Wrapper (YAJSW). Based on the JDK version, you have to download the two different versions of YAJSW as follows.

  • If you are using JDK 8, then you need to download the YAJSW 11.03 version.
  • If you are using JDK 11, then you need to download the YAJSW 12.14 version.

Here I am using JDK 11 and we are using YAJSW 12.14 version.

Setting up the YAJSW wrapper configuration file

  1. Download YAJSW 12.14 and unzip it.
  2. Go to the <YAJSW_HOME>/conf/ and open the “wrapper.conf” by using a text editor.
  3. Put the below content in the “wrapper.conf” file and save it. This contains the minimal configurations for running a WSO2 product as a Windows service.
#********************************************************************
# working directory
#********************************************************************
wrapper.working.dir=${carbon_home}/
# Java Main class.
# YAJSW: default is "org.rzo.yajsw.app.WrapperJVMMain"
# DO NOT SET THIS PROPERTY UNLESS YOU HAVE YOUR OWN IMPLEMENTATION
# wrapper.java.mainclass=
#********************************************************************
# tmp folder
# yajsw creates temporary files named in_.. out_.. err_.. jna..
# per default these are placed in jna.tmpdir.
# jna.tmpdir is set in setenv batch file to <yajsw>/tmp
#********************************************************************
wrapper.tmp.path = ${jna_tmpdir}
#********************************************************************
# Application main class or native executable
# One of the following properties MUST be defined
#********************************************************************
# Java Application main class
wrapper.java.app.mainclass=org.wso2.carbon.bootstrap.Bootstrap
# Log Level for console output. (See docs for log levels)
wrapper.console.loglevel=INFO
# Log file to use for wrapper output logging.
wrapper.logfile=${wrapper_home}\/log\/wrapper.log
# Format of output for the log file. (See docs for formats)
#wrapper.logfile.format=LPTM
# Log Level for log file output. (See docs for log levels)
#wrapper.logfile.loglevel=INFO
# Maximum size that the log file will be allowed to grow to before
# the log is rolled. Size is specified in bytes. The default value
# of 0, disables log rolling by size. May abbreviate with the 'k' (kB) or
# 'm' (mB) suffix. For example: 10m = 10 megabytes.
# If wrapper.logfile does not contain the string ROLLNUM it will be automatically added as suffix of the file name
wrapper.logfile.maxsize=10m
# Maximum number of rolled log files which will be allowed before old
# files are deleted. The default value of 0 implies no limit.
wrapper.logfile.maxfiles=10
# Title to use when running as a console
wrapper.console.title=WSO2 Carbon
#********************************************************************
# Wrapper Windows Service and Posix Daemon Properties
#********************************************************************
# Name of the service
wrapper.ntservice.name=WSO2CARBON
# Display name of the service
wrapper.ntservice.displayname=WSO2 Carbon
# Description of the service
wrapper.ntservice.description=Carbon Kernel
#********************************************************************
# Wrapper System Tray Properties
#********************************************************************
# enable system tray
wrapper.tray = true
# TCP/IP port. If none is defined multicast discovery is used to find the port
# Set the port in case multicast is not possible.
wrapper.tray.port = 15002
#********************************************************************
# Exit Code Properties
# Restart on non zero exit code
#********************************************************************
wrapper.on_exit.0=SHUTDOWN
wrapper.on_exit.default=RESTART
#********************************************************************
# Trigger actions on console output
#********************************************************************
# On Exception show message in system tray
wrapper.filter.trigger.0=Exception
wrapper.filter.script.0=${wrapper_home}/scripts/trayMessage.gv
wrapper.filter.script.0.args=Exception
#********************************************************************
# genConfig: further Properties generated by genConfig
#********************************************************************
placeHolderSoGenPropsComeHere=
wrapper.java.command = java
wrapper.java.classpath.1 = ${carbon_home}/bin/*.jar
wrapper.java.classpath.2 = ${carbon_home}/lib/commons-lang-*.jar
wrapper.java.classpath.3 = ${carbon_home}/lib/*.jar
wrapper.app.parameter.1 = org.wso2.carbon.bootstrap.Bootstrap
wrapper.app.parameter.2 = RUN
wrapper.java.additional.1 = -Xbootclasspath/a:${carbon_home}/lib/xboot/*.jar
wrapper.java.additional.2 = -Xms256m
wrapper.java.additional.3 = -Xmx1024m
wrapper.java.additional.4 = -XX:MaxPermSize=256m
wrapper.java.additional.5 = -XX:+HeapDumpOnOutOfMemoryError
wrapper.java.additional.6 = -XX:HeapDumpPath=${carbon_home}/repository/logs/heap-dump.hprof
wrapper.java.additional.7 = -Dcom.sun.management.jmxremote
wrapper.java.additional.8 = -Dcarbon.registry.root=\/
wrapper.java.additional.9 = -Dcarbon.home=${carbon_home}
wrapper.java.additional.10 = -Dwso2.server.standalone=true
wrapper.java.additional.11 = -Djava.command=${java_home}/bin/java
wrapper.java.additional.12 = -Djava.io.tmpdir=${carbon_home}/tmp
wrapper.java.additional.13 = -Dcatalina.base=${carbon_home}/lib/tomcat
wrapper.java.additional.14 = -Djava.util.logging.config.file=${carbon_home}/repository/conf/etc/logging-bridge.properties
wrapper.java.additional.15 = -Dcarbon.config.dir.path=${carbon_home}/repository/conf
wrapper.java.additional.16 = -Dcarbon.logs.path=${carbon_home}/repository/logs
wrapper.java.additional.17 = -Dcomponents.repo=${carbon_home}/repository/components/plugins
wrapper.java.additional.18 = -Dconf.location=${carbon_home}/repository/conf
wrapper.java.additional.19 = -Dcom.atomikos.icatch.file=${carbon_home}/lib/transactions.properties
wrapper.java.additional.20 = -Dcom.atomikos.icatch.hide_init_file_path=true
wrapper.java.additional.21 = -Dorg.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER=true
wrapper.java.additional.22 = -Dcom.sun.jndi.ldap.connect.pool.authentication=simple
wrapper.java.additional.23 = -Dcom.sun.jndi.ldap.connect.pool.timeout=3000
wrapper.java.additional.24 = -Dorg.terracotta.quartz.skipUpdateCheck=true
wrapper.java.additional.25 = -Dorg.apache.jasper.compiler.Parser.STRICT_QUOTE_ESCAPING=false
wrapper.java.additional.26 = -Dfile.encoding=UTF8
wrapper.java.additional.27 = -DworkerNode=false
wrapper.java.additional.28 = -Dhttpclient.hostnameVerifier=DefaultAndLocalhost
wrapper.java.additional.29 = -Dcarbon.new.config.dir.path=${carbon_home}/repository/resources/conf
wrapper.java.additional.30 = -Dinstance.log=""

4. Add the following class path to the “wrapper.conf” file to avoid errors in the WSO2 API Manager Management Console:

wrapper.java.classpath.4 = ${carbon_home}/repository/components/plugins/commons-lang_2.6.0.wso2v1.jar

The above config is fixing the management console returning a 500 Internal when updating “Advance Configuration” for Local & Outbound Configuration.

Setting up carbon_home

Once complete the configurations on the YAJSW, you need to configure the carbon_home as an environment available in the windows.

  1. Create an environment variable, which named as “carbon_home”. This must be defined in lower case. Please don’t use upper case (CARBON_HOME).
  2. The value of the carbon_home is path for the APIM 3.0.0 home and apply it.
carbon_home=<AM_HOME>
eg: carbon_home=C:\wso2_products\apim\wso2am-3.0.0

Running the product in console mode

Here you can find whether you have configured the “wrapper.conf” file correctly or not. If configurations are ok, you will able to start the WSO2 APIM as console mode. Please follow the below steps.

  1. Open a Windows command prompt and go to the <YAJSW_HOME>/bat/ directory.
eg: cd Settings\yajsw-stable-12.14\bat

2. Start the wrapper in console mode using the following command:

runConsole.bat

If no issues in the “wrapper.conf” file, you would start the server without any issue, and you could log to the management console, publisher and Devportal without any issues.

If no issues, you can start the wso2 server as windows service by following the below steps.

Working with the WSO2CARBON service

Before starting the below steps, please make sure to stop the runConsole.bat which we started in the previous step. Furthermore, in order to run the service, the windows user must have al least permissions for installing, starting and stopping a windows service. If you are an admin user, no worries you can continue the following steps without any issue.

  1. To install the Carbon-based product WSO2 API Manager as a Windows service, execute the following command in the <YAJSW_HOME>/bat/ directory.
installService.bat

If service is successfully installed, it will show a message in the command line. As well as, you can see a carbon_service in the windows “Services” list.

2. To start the service, execute the following command at the <YAJSW_HOME>/bat/ directory. Otherwise, you can select the service from the “Services” list and start by right click on that.

startService.bat

3. If you want to stop the service, you can run the below command at the <YAJSW_HOME>/bat/ directory.

stopService.bat

4. If you want to install the service, you need to execute the below command in the <YAJSW_HOME>/bat/ directory.

uninstallService.bat

Important: However, if you did any change in the “wrapper.conf” file, please make sure to stop and uninstall the existing service and reinstall and start the service back to reflect that change on the server.

Common errors and Solutions

While following the above steps, you may be faced below errors.

  1. WARNING|wrapper|”WSO2 Carbon”|working directory ?unresolved?/ not found

The above “working directory ?unresolved?/ not found” is coming when you haven’t set the carbon_home or haven’t set the carbon_home properly. Please check the “Setting up carbon_home” section of this blog to verify the steps.

2. You have started the service successfully, but when you logging to the Publisher or Devportal, you may see SSL errors as follows.

ERROR {org.jaggeryjs.jaggery.core.manager.WebAppManager} - org.mozilla.javascript.WrappedException: Wrapped org.jaggeryjs.scriptengine.exceptions.ScriptException: javax.net.ssl.SSLPeerUnverifiedException: SSL peer failed hostname validation for name: localhost (<<http>>/META-INF/scripts/http.js#220) org.jaggeryjs.scriptengine.exceptions.ScriptException: org.mozilla.javascript.WrappedException: Wrapped org.jaggeryjs.scriptengine.exceptions.ScriptException: javax.net.ssl.SSLPeerUnverifiedException: SSL peer failed hostname validation for name: localhost (<<http>>/META-INF/scripts/http.js#220)
at org.jaggeryjs.scriptengine.engine.RhinoEngine.execScript(RhinoEngine.java:587)

The above exception occurs due to the internal API calls which occur during login. The hostname used for these internal calls are set to ‘localhost’ in the
<HOME>/repository/deployment/server/jaggeryapps/<PUBLISHER/DEVPORTAL>/site/public/theme/settings.js file of the respective portal as shown in the below.

  • Publisher Node: Under the <APIM_HOME>/repository/deployment/server/jaggeryapps/publisher/site/public/theme/settings.js
const Settings = {
app: {
context: '/publisher',
customUrl: {
enabled: false,
forwardedHeader: 'X-Forwarded-For',
},
origin: {
host: 'localhost',
},
},
};
  • Devportal Node: Under the <APIM_HOME>/repository/deployment/server/jaggeryapps/devportal/site/public/theme/settings.js
const Settings = {
app: {
context: '/devportal',
customUrl: {
enabled: false,
forwardedHeader: 'X-Forwarded-For',
},
origin: {
host: 'localhost',
},
subscriptionLimit: 1000,
},
grantTypes: {
...,
},
};

The reason for this issue is, there is no valid certificate for the hostname ‘localhost’ in the client-truststore.jks.

This can be resolved by setting the hostname configured in the deployment.yaml as the host entry in the settings.js file.

eg:

  • Publisher: Go to the <APIM_HOME>/repository/deployment/server/jaggeryapps/publisher/site/public/theme/settings.js
const Settings = {
app: {
context: '/publisher',
customUrl: {
enabled: false,
forwardedHeader: 'X-Forwarded-For',
},
origin: {
host: 'host_name_as_in_deployment_toml_file',
},
},
};
  • Devportal: Go to the <APIM_HOME>/repository/deployment/server/jaggeryapps/devportal/site/public/theme/settings.js
const Settings = {
app: {
context: '/devportal',
customUrl: {
enabled: false,
forwardedHeader: 'X-Forwarded-For',
},
origin: {
host: 'host_name_as_in_deployment_toml_file',
},
subscriptionLimit: 1000,
},
grantTypes: {
...,
},
};

Save the changes and try to log in to the publisher and devportal. The above SSL issue will be fixed.

Now you can work with the APIM server without any issue. Please try out this and let me know the feedback.

Hope this will be a useful story for you. Appreciate your claps and will meet with another story soon :) bye.

References

[1]. https://mkyong.com/java/how-to-set-java_home-on-windows-10/

Senior Software Engineer at WSO2