Configure data sources for a Tomcat, JBoss, or Java SE app in Azure App Service
This article shows how to configure data sources in a Java SE, Tomcat, or JBoss app in App Service.
Azure App Service runs Java web applications on a fully managed service in three variants:
- Java SE - Can run an app deployed as a JAR package that contains an embedded server (such as Spring Boot, Dropwizard, Quarkus, or one with an embedded Tomcat or Jetty server).
- Tomcat - The built-in Tomcat server can run an app deployed as a WAR package.
- JBoss EAP - Supported for Linux apps in the Free, Premium v3, and Isolated v2 pricing tiers only. The built-in JBoss EAP server can run an app deployed as a WAR or EAR package.
Note
For Spring applications, we recommend using Azure Spring Apps. However, you can still use Azure App Service as a destination. See Java Workload Destination Guidance for advice.
Configure the data source
To connect to data sources in Spring Boot applications, we suggest creating connection strings and injecting them into your application.properties file.
In the "Configuration" section of the App Service page, set a name for the string, paste your JDBC connection string into the value field, and set the type to "Custom". You can optionally set this connection string as slot setting.
This connection string is accessible to our application as an environment variable named
CUSTOMCONNSTR_<your-string-name>
. For example,CUSTOMCONNSTR_exampledb
.In your application.properties file, reference this connection string with the environment variable name. For our example, we would use the following code:
app.datasource.url=${CUSTOMCONNSTR_exampledb}
For more information, see the Spring Boot documentation on data access and externalized configurations.
Tip
By default, the Linux Tomcat containers can automatically configure shared data sources for you in the Tomcat server. The only thing for you to do is add an app setting that contains a valid JDBC connection string to an Oracle, SQL Server, PostgreSQL, or MySQL database (including the connection credentials), and App Service automatically adds the corresponding shared database to /usr/local/tomcat/conf/context.xml, using an appropriate driver available in the container. For an end-to-end scenario using this approach, see Tutorial: Build a Tomcat web app with Azure App Service on Linux and MySQL.
These instructions apply to all database connections. You need to fill placeholders with your chosen database's driver class name and JAR file. Provided is a table with class names and driver downloads for common databases.
Database | Driver Class Name | JDBC Driver |
---|---|---|
PostgreSQL | org.postgresql.Driver |
Download |
MySQL | com.mysql.jdbc.Driver |
Download (Select "Platform Independent") |
SQL Server | com.microsoft.sqlserver.jdbc.SQLServerDriver |
Download |
To configure Tomcat to use Java Database Connectivity (JDBC) or the Java Persistence API (JPA), first customize the CATALINA_OPTS
environment variable that is read in by Tomcat at start-up. Set these values through an app setting in the App Service Maven plugin:
<appSettings>
<property>
<name>CATALINA_OPTS</name>
<value>"$CATALINA_OPTS -Ddbuser=${DBUSER} -Ddbpassword=${DBPASSWORD} -DconnURL=${CONNURL}"</value>
</property>
</appSettings>
Or set the environment variables in the Configuration > Application Settings page in the Azure portal.
Next, determine if the data source should be available to one application or to all applications running on the Tomcat servlet.
Application-level data sources
Create a context.xml file in the META-INF/ directory of your project. Create the META-INF/ directory if it doesn't exist.
In context.xml, add a
Context
element to link the data source to a JNDI address. Replace thedriverClassName
placeholder with your driver's class name from the table above.<Context> <Resource name="jdbc/dbconnection" type="javax.sql.DataSource" url="${connURL}" driverClassName="<insert your driver class name>" username="${dbuser}" password="${dbpassword}" /> </Context>
Update your application's web.xml to use the data source in your application.
<resource-env-ref> <resource-env-ref-name>jdbc/dbconnection</resource-env-ref-name> <resource-env-ref-type>javax.sql.DataSource</resource-env-ref-type> </resource-env-ref>
Shared server-level resources
Adding a shared, server-level data source requires you to edit Tomcat's server.xml. The most reliable way to do this is as follows:
- Upload a startup script and set the path to the script in Configuration > Startup Command. You can upload the startup script using FTP.
Your startup script makes an xsl transform to the server.xml file and output the resulting xml file to /usr/local/tomcat/conf/server.xml
. The startup script should install libxslt via apk. Your xsl file and startup script can be uploaded via FTP. Below is an example startup script.
# Install libxslt. Also copy the transform file to /home/tomcat/conf/
apk add --update libxslt
# Usage: xsltproc --output output.xml style.xsl input.xml
xsltproc --output /home/tomcat/conf/server.xml /home/tomcat/conf/transform.xsl /usr/local/tomcat/conf/server.xml
The following example XSL file adds a new connector node to the Tomcat server.xml.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()" name="Copy">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@* | node()" mode="insertConnector">
<xsl:call-template name="Copy" />
</xsl:template>
<xsl:template match="comment()[not(../Connector[@scheme = 'https']) and
contains(., '<Connector') and
(contains(., 'scheme="https"') or
contains(., "scheme='https'"))]">
<xsl:value-of select="." disable-output-escaping="yes" />
</xsl:template>
<xsl:template match="Service[not(Connector[@scheme = 'https'] or
comment()[contains(., '<Connector') and
(contains(., 'scheme="https"') or
contains(., "scheme='https'"))]
)]
">
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="insertConnector" />
</xsl:copy>
</xsl:template>
<!-- Add the new connector after the last existing Connector if there's one -->
<xsl:template match="Connector[last()]" mode="insertConnector">
<xsl:call-template name="Copy" />
<xsl:call-template name="AddConnector" />
</xsl:template>
<!-- ... or before the first Engine if there's no existing Connector -->
<xsl:template match="Engine[1][not(preceding-sibling::Connector)]"
mode="insertConnector">
<xsl:call-template name="AddConnector" />
<xsl:call-template name="Copy" />
</xsl:template>
<xsl:template name="AddConnector">
<!-- Add new line -->
<xsl:text>
</xsl:text>
<!-- This is the new connector -->
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
keystoreFile="${{user.home}}/.keystore" keystorePass="changeit"
clientAuth="false" sslProtocol="TLS" />
</xsl:template>
</xsl:stylesheet>
Finalize configuration
Finally, place the driver JARs in the Tomcat classpath and restart your App Service.
- Ensure that the JDBC driver files are available to the Tomcat classloader by placing them in the /home/site/lib directory. In the Cloud Shell, run
az webapp deploy --type=lib
for each driver JAR:
az webapp deploy --resource-group <group-name> --name <app-name> --src-path <jar-name>.jar --type=lib --path <jar-name>.jar
If you created a server-level data source, restart the App Service Linux application. Tomcat resets CATALINA_BASE
to /home/tomcat
and uses the updated configuration.
Tip
By default, the Linux JBoss containers can automatically configure shared data sources for you in the JBoss server. The only thing for you to do is add an app setting that contains a valid JDBC connection string to an Oracle, SQL Server, PostgreSQL, or MySQL database (including the connection credentials), and App Service automatically adds the corresponding shared data source, using an appropriate driver available in the container. For an end-to-end scenario using this approach, see Tutorial: Build a JBoss web app with Azure App Service on Linux and MySQL.
There are three core steps when registering a data source with JBoss EAP:
- Upload the JDBC driver.
- Add the JDBC driver as a module.
- Add a data source with the module.
App Service is a stateless hosting service, so you must put these steps into a startup script and run it each time the JBoss container starts. Using PostgreSQL, MySQL, and SQL Database as an examples:
Put your JBoss CLI commands into a file named jboss-cli-commands.cli. The JBoss commands must add the module and register it as a data source. The following example shows the JBoss CLI commands for creating a PostgreSQL data source with the JNDI name
java:jboss/datasources/postgresDS
.module add --name=org.postgresql --resources=/home/site/libs/postgresql-42.7.4.jar /subsystem=datasources/jdbc-driver=postgresql:add(driver-name="postgresql",driver-module-name="org.postgresql",driver-class-name="org.postgresql.Driver",driver-xa-datasource-class-name="org.postgresql.xa.PGXADataSource") data-source add --name=postgresql --driver-name="postgresql" --jndi-name="java:jboss/datasources/postgresDS" --connection-url="jdbc:postgresql://\${env.DB_HOST}:5432/postgres" --user-name="\${env.DB_USERNAME}" --password="\${env.DB_PASSWORD}" --enabled=true --use-java-context=true
Note that the
module add
command uses three environment variables (DB_HOST
,DB_USERNAME
, andDB_PASSWORD
), which you must add in App Service as app settings. The script adds them without the--resolve-parameter-values
flag so that JBoss doesn't save their values in plaintext.Create a startup script, startup.sh, that calls the JBoss CLI commands. The following example shows how to call your
jboss-cli-commands.cli
. Later, you'll configure App Service to run this script when the container starts.$JBOSS_HOME/bin/jboss-cli.sh --connect --file=/home/site/scripts/jboss_cli_commands.cli
Using a deployment option of your choice, upload your JDBC driver, jboss-cli-commands.cli, and startup.sh to the paths specified in the respective scripts. Especially, upload startup.sh as a startup file. For example:
export RESOURCE_GROUP_NAME=<resource-group-name> export APP_NAME=<app-name> # The lib type uploads to /home/site/libs by default. az webapp deploy --resource-group $RESOURCE_GROUP_NAME --name $APP_NAME --src-path postgresql-42.7.4.jar --target-path postgresql-42.7.4.jar --type lib az webapp deploy --resource-group $RESOURCE_GROUP_NAME --name $APP_NAME --src-path jboss_cli_commands.cli --target-path /home/site/scripts/jboss_cli_commands.cli --type static # The startup type uploads to /home/site/scripts/startup.sh by default. az webapp deploy --resource-group $RESOURCE_GROUP_NAME --name $APP_NAME --src-path startup.sh --type startup
For more information, see Deploy files to App Service.
To confirm that the data source was added to the JBoss server, SSH into your webapp and run $JBOSS_HOME/bin/jboss-cli.sh --connect
. Once you're connected to JBoss, run the /subsystem=datasources:read-resource
to print a list of the data sources.
As defined by jboss-cli-commands.cli previously, you can access the PostgreSQL connection using the JNDI name java:jboss/datasources/postgresDS
.
Next steps
Visit the Azure for Java Developers center to find Azure quickstarts, tutorials, and Java reference documentation.