We have access to the tomcat manager app restricted by authentication and IP address. See example config:
<Context docBase="${catalina.home}/server/webapps/manager"
privileged="true" antiResourceLocking="false">
<Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="{some-ips}"/>
<!-- Link to the user database we will get roles from -->
<ResourceLink name="users" global="UserDatabase"
type="org.apache.catalina.UserDatabase"/>
</Context>
Is there any way to reference an additional file on the local machine that determines additional IP addresses that are allowed to access the manager app?
Thanks.
Related
How to deploy the same application to multiple contexts, each with a different database.
Using Tomcat7.0.54. We have 3 different environments like Development, Quality, Production. All the 3 environments have 3 different database configurations.
Normally apache-tomcat-7.0.54\conf\context.xml file. Sample D config.
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
<!-- Uncomment this to enable Comet connection tacking (provides events
on session expiration as well as webapp lifecycle) -->
<!--
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
-->
<Resource name="java:jboss/datasources/letterDatasource"
auth="Container"
type="javax.sql.DataSource"
username="admin"
password="admin"
driverClassName="oracle.jdbc.OracleDriver"
url="xxx xxxx xxxxx xx"
maxActive="8"
maxIdle="4"/>
How to do the above programmatically or efficiently instead of changing in every server context.xml file.?
i am not using spring. just normal web application using seam 2.3 with jsf and richfaces.
Thank you.
Keep your data base properties in an environment.property file, which will be different for each stage. Specified environment will take their specific environmental properties.
A Java Servlet-jsp app running on on-premise hardware is to be migrated to pivotal cloud PaaS.
Currently, the app takes DB credentials from server.xml of Tomcat and the resource is added in the context.xml.
This is the context.xml
<ResourceLink name="jdbc/db"
global="jdbc/db"
auth="Container"
type="javax.sql.DataSource" />
This is server.xml
<Resource name="jdbc/db"
global="jdbc/db"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://HOST:3306/db"
username="..."
password="..."
maxActive="100"
maxIdle="20"
minIdle="5"
maxWait="10000"/>
How can I pass the Credentials to the server? Is there any standard way to pass DB credentials for PaaS applications?
Your Spring Boot application will be packaged as an executable JAR. It'll have an application.yml file inside it that contains your database connection credentials.
You can also configure your data source as a Pivotal Cloud Foundry service. That way the credentials are added to the cloud. Your app simply refers to them.
I have the war file of my application. I need to deploy this at the root level. The current URL is http://localhost:8080/war_name/application_name.
You have a couple of options:
Remove the out-of-the-box ROOT/ directory from tomcat and rename your war file to ROOT.war before deploying it.
Deploy your war as (from your example) war_name.war and configure the context root in conf/server.xml to use your war file :
<Context path="" docBase="war_name" debug="0" reloadable="true"></Context>
The first one is easier, but a little more kludgy. The second one is probably the more elegant way to do it.
on tomcat v.7 (vanilla installation)
in your conf/server.xml add the following bit towards the end of the file, just before the </Host> closing tag:
<Context path="" docBase="app_name">
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>
Note that docBase attribute. It's the important bit. You either make sure you've deployed app_name before you change your root web app, or just copy your unpacked webapp (app_name) into your tomcat's webapps folder. Startup, visit root, see your app_name there!
In tomcat 7 with these changes, i'm able to access myAPP at / and ROOT at /ROOT
<Context path="" docBase="myAPP">
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>
<Context path="ROOT" docBase="ROOT">
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>
Add above to the <Host> section in server.xml
I know that my answer is kind of overlapping with some of the other answer, but this is a complete solution that has some advantages. This works on Tomcat 8:
The main application is served from the root
The deployment of war files through the web interface is maintained.
The main application will run on port 80 while only the admins have access to the managment folders (I realize that *nix systems require superuser for binding to 80, but on windows this is not an issue).
This means that you only have to restart the tomcat once, and after updated war files can be deployed without a problem.
Step 1:
In the server.xml file, find the connector entry and replace it with:
<Connector
port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector
port="80"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
Step 2:
Define contexts within the <Host ...> tag:
<Context path="/" docBase="CAS">
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>
<Context path="/ROOT" docBase="ROOT">
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>
<Context path="/manager" docBase="manager" privileged="true">
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>
<Context path="/host-manager" docBase="host-manager" privileged="true">
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>
Note that I addressed all apps in the webapp folder. The first effectively switch the root and the main app from position. ROOT is now on http://example.com/ROOT and the the main application is on http://example.com/. The webapps that are password protected require the privileged="true" attribute.
When you deploy a CAS.war file that matches with the root (<Context path="/" docBase="CAS"> you have to reload that one in the admin panel as it does not refresh with the deployment.
Do not include the <Context path="/CAS" docBase="CAS"> in your contexts as it disables the manager option to deploy war files. This means that you can access the app in two ways: http://example.com/ and http://example.com/APP/
Step 3:
In order to prevent unwanted access to the root and manager folder, add a valve to those context tags like this:
<Context path="/manager" docBase="manager" privileged="true">
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
addConnectorPort="true"
allow="143\.21\.2\.\d+;8080|127\.0\.0\.1;8080|::1;8080|0:0:0:0:0:0:0:1;8080"/>
</Context>
This essentially limits access to the admin web app folder to people from my own domain (fake IP address) and localhost when they use the default port 8080 and maintains the ability to dynamically deploy the war files through the web interface.
If you want to use this for multiple apps that are using different IP addresses, you can add the IP address to the connector (address="143.21.2.1").
If you want to run multiple web apps from the root, you can duplicate the Service tag (use a different name for the second) and change the docbase of the <Context path="/" docBase="CAS"> to for example <Context path="/" docBase="ICR">.
Remove $CATALINA_HOME/webapps/ROOT. Update $CATALINA_HOME/conf/server.xml, make sure that Host element look like the following text:
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="false" deployOnStartup="false">
<Context path="" docBase="myApp"></Context>
It works with Tomcat 8. autoDeploy and deployOnStartup need to set to false to prevent tomcat from deploying myApp twice.
The fastest way.
Make sure you don't have ROOT app deployed, undeploy if you have one
Rename your war to ROOT.war, deploy, thats all, no configuration changes needed
Adding to #Dima's answer, if you're using maven to build your package, you can tell it to set your WAR file name to ROOT in pom.xml:
<build>
<finalName>ROOT</finalName>
</build>
By default, tomcat will deploy ROOT.war webapp into root context (/).
Adding on to #Rob Hruska's sol, this setting in server.xml inside section works:
<Context path="" docBase="gateway" reloadable="true" override="true"> </Context>
Note: override="true" might be required in some cases.
open tomact manager url :- http://localhost:8080/manager/html/
then in applications you see a application having path as "/" is deployed simply Undeploy this.
Rename your application's war file as ROOT.war and just place at path :- C:\Program Files\Apache Software Foundation\Tomcat 8.5\webapps
start your Tomcat No extra configuration needed.
Now we can see our application home page or configured url at http://localhost:8080
In my server I am using this and root autodeploy works just fine:
<Host name="mysite" autoDeploy="true" appBase="webapps" unpackWARs="true" deployOnStartup="true">
<Alias>www.mysite.com</Alias>
<Valve className="org.apache.catalina.valves.RemoteIpValve" protocolHeader="X-Forwarded-Proto"/>
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="mysite_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b"/>
<Context path="/mysite" docBase="mysite" reloadable="true"/>
</Host>
for example app.war. I want to change root url for ruuning program on it.
I am absolutely confused. I tried out to specify root url in context.xml(in my app folder, and I've tried to add ROOT.xml. But it doesn't work(in general, I don't know where I make mistake of changing parametrs, I've looked over all tips. If i change in /web-inf context.xml, then tomcat removes all changing. Tomcat doesn't see ROOT.xml in specific folder. Please, may be someone can write more explicitly these steps and explain some things, which happened with me preventing my Tomcat from working correctly.
this is C:\Users\user\Desktop\psc\ProductCatalog\psc-ui\target\tomcat\conf\context.xml below
<Context>
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
<!-- Uncomment this to enable Comet connection tacking (provides events
on session expiration as well as webapp lifecycle) -->
<!--
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
-->
<Environment name="SQL.log" value="DEBUG" type="java.lang.String"/>
this is C:\Users\Alexander.Luchko\Desktop\psc\ProductCatalog\psc-ui\target\ProductCatalog\META-INF\context.xml below
<Context>
<Parameter name="javax.faces.PROJECT_STAGE" value="Production" override="false"/>
........
<Resource ....
sorry for my bad english! in advance
I am trying to set up the database connection properties using JNDI for a Spring web application.
I am considering two approaches as below:
Approach 1:
In your Spring configuration you may have something like:
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/facs"/>
Then in your webapp /META-INF/context.xml file you should have something similar too:
<?xml version='1.0' encoding='utf-8'?>
<!-- antiResourceLocking="true" -->
<Context path="/podd-apn"
reloadable="true"
cachingAllowed="false"
antiResourceLocking="true"
>
<Resource name="jdbc/facs"
type="javax.sql.DataSource" username="${database.username}" password="${database.password}"
driverClassName="org.postgresql.Driver"
url="${database.url}"
maxActive="8" maxIdle="4"
global="jdbc/facs"
/>
</Context>
And in your web.xml you should something like:
<!-- JNDI -->
<resource-ref>
<description>FACs Datasource</description>
<res-ref-name>jdbc/facs</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Approach 2:
Setup in the Spring context like this:
<jee:jndi-lookup id="dbDataSource"
jndi-name="jdbc/DatabaseName"
expected-type="javax.sql.DataSource" />
You can declare the JNDI resource in Tomcat's server.xml using something like this:
<GlobalNamingResources>
<Resource name="jdbc/DatabaseName" auth="Container" type="javax.sql.DataSource"
username="dbUsername" password="dbPasswd"
url="jdbc:postgresql://localhost/dbname"
driverClassName="org.postgresql.Driver"
initialSize="5" maxWait="5000"
maxActive="120" maxIdle="5"
validationQuery="select 1"
poolPreparedStatements="true"/>
</GlobalNamingResources/>
And reference the JNDI resource from Tomcat's web context.xml like this:
<ResourceLink name="jdbc/DatabaseName"
global="jdbc/DatabaseName"
type="javax.sql.DataSource"/>
My question is where is the best place to keep database properties? Should they be placed in server.xml or context.xml?
Also, if I have 2 databases, should I use two configs?
Also, is it best practice to directly place them in either server.xml or context.xml? Or do I need to configure through Tomcat Manager GUI console?
Thanks!
I prefer a third approach that takes the best from
Approach 1 and Approach 2 described by user1016403.
Approach 3
Save database properties on the server.xml
reference the server.xml database properties from the web application META-INF/context.xml
Approach 3 benefits
While the first point is useful for security reasons the second point is useful for referencing server properties value from the web application, even if server properties values will change.
Moreover decoupling resource definitions on the server from their use by the web application makes such configuration scalable across organizations with various complexity where different teams work on different tiers/layers: the server administrators team can work without conflicting with developers team if the administrator shares the same JNDI name with the developer for each resource.
Approach 3 implementation
Define the JNDI name jdbc/ApplicationContext_DatabaseName.
Declare the jdbc/ApplicationContext_DatabaseName's various properties and values in Tomcat's server.xml using something like this:
<GlobalNamingResources>
<Resource name="jdbc/ApplicationContext_DatabaseName" auth="Container" type="javax.sql.DataSource"
username="dbUsername" password="dbPasswd"
url="jdbc:postgresql://localhost/dbname"
driverClassName="org.postgresql.Driver"
initialSize="5" maxWait="5000"
maxActive="120" maxIdle="5"
validationQuery="select 1"
poolPreparedStatements="true"/>
</GlobalNamingResources/>
Link the jdbc/ApplicationContext_DatabaseName's properties from web application META-INF/context.xml by an application-private JNDI context java:comp/env/ specified in the name attribute:
<Context path="/ApplicationContext" ... >
<!--
"global" attribute links to GlobalNamingResources in the ${catalina.base}/conf/server.xml (server administrator team)
"name" attribute is relative to the application-private JNDI context java:comp/env/ and is looked up from the java web application (application developer team)
-->
<ResourceLink global="jdbc/ApplicationContext_DatabaseName" name="jdbc/DatabaseName" type="javax.sql.DataSource"/>
</Context>
Finally, in order to use the JNDI resource, specify the JNDI name jdbc/DatabaseName in web application's deployment descriptor:
<resource-ref>
<description>DatabaseName's Datasource</description>
<res-ref-name>jdbc/DatabaseName</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
and in Spring context:
<jee:jndi-lookup id="DatabaseNameDataSource"
jndi-name="jdbc/DatabaseName"
expected-type="javax.sql.DataSource" />
Approach 3 drawbacks
If the JNDI name gets changed then both the server.xml and the META-INF/context.xml will have to be edited and a deploy would be necessary; nevertheless this scenario is rare.
Approach 3 variations
Many data sources used by one web application
Simply add configurations to Tomcat's server.xml:
<GlobalNamingResources>
<Resource name="jdbc/ApplicationContext_DatabaseName1" ... />
<Resource name="jdbc/ApplicationContext_DatabaseName2" ... />
...
</GlobalNamingResources/>
Add link web application META-INF/context.xml by an application-private JNDI context java:comp/env/ specified in the name attribute:
<Context path="/ApplicationContext" ... >
<ResourceLink global="jdbc/ApplicationContext_DatabaseName1" name="jdbc/DatabaseName1" ... />
<ResourceLink global="jdbc/ApplicationContext_DatabaseName2" name="jdbc/DatabaseName2" ... />
...
</Context>
Finally add JNDI resources usage in web application's deployment descriptor:
<resource-ref>
<description>DatabaseName1's Datasource</description>
<res-ref-name>jdbc/DatabaseName1</res-ref-name> ...
</resource-ref>
<resource-ref>
<description>DatabaseName2's Datasource</description>
<res-ref-name>jdbc/DatabaseName2</res-ref-name> ...
</resource-ref>
...
and in Spring context:
<jee:jndi-lookup id="DatabaseName1DataSource"
jndi-name="jdbc/DatabaseName1" ... />
<jee:jndi-lookup id="DatabaseName2DataSource"
jndi-name="jdbc/DatabaseName2" ... />
...
Many data sources used by many web application on the same server
Simply add configuration to Tomcat's server.xml:
<GlobalNamingResources>
<Resource name="jdbc/ApplicationContextX_DatabaseName1" ... />
<Resource name="jdbc/ApplicationContextX_DatabaseName2" ... />
<Resource name="jdbc/ApplicationContextY_DatabaseName1" ... />
<Resource name="jdbc/ApplicationContextY_DatabaseName2" ... />
...
</GlobalNamingResources/>
the others configuration should be deducible from previous variation case.
Many data sources to the same database used by many web application on the same server
In such case a Tomcat's server.xml configurations like:
<GlobalNamingResources>
<Resource name="jdbc/ApplicationContextX_DatabaseName" ... />
<Resource name="jdbc/ApplicationContextY_DatabaseName" ... />
ends up in two different web applications META-INF/context.xml like:
<Context path="/ApplicationContextX" ... >
<ResourceLink global="jdbc/ApplicationContextX_DatabaseName" name="jdbc/DatabaseName" ... />
</Context>
and like:
<Context path="/ApplicationContextY" ... >
<ResourceLink global="jdbc/ApplicationContextY_DatabaseName" name="jdbc/DatabaseName" ... />
</Context>
so someone might be worried about the fact that the same name="jdbc/DatabaseName" is looked up, and then used, by two different applications deployed on the same server: this is not a problem because the jdbc/DatabaseName is an application-private JNDI context java:comp/env/, so ApplicationContextX by using java:comp/env/ can't (by design) look up the resource linked to global="jdbc/ApplicationContextY_DatabaseName".
Of course if you felt more relaxed without this worry you might use a different naming strategy like:
<Context path="/ApplicationContextX" ... >
<ResourceLink global="jdbc/ApplicationContextX_DatabaseName" name="jdbc/applicationXprivateDatabaseName" ... />
</Context>
and like:
<Context path="/ApplicationContextY" ... >
<ResourceLink global="jdbc/ApplicationContextY_DatabaseName" name="jdbc/applicationYprivateDatabaseName" ... />
</Context>
YOUR_APP.xml file
I prefer Approach 2 (put everything (not only some attribute in the config), but instead of placing them in the global server.xml or global context.xml you should place it in the application-specific context.xml.default YOUR_APP.xml file in your Tomcat.
The YOUR_APP.xml file is located in $catalinaHome/conf/<engine>/<host> (for example conf/Catalina/localhost/YOUR_APP.xml).
The configuration in application specific YOUR_APP.xml is only available for the specific application.
See the guide published by MuleSoft. And see the official documentation, Tomcat Configuration Reference, page for The Context Container
Version 9
Version 8
To quote that documentation:
Individual Context elements may be explicitly defined:
• …
• In individual files (with a ".xml" extension) in the $CATALINA_BASE/conf/[enginename]/[hostname]/ directory. The context path and version will be derived from the base name of the file (the file name less the .xml extension).
• …
Approach 4
Instead of using JNDI I work with .properties files and build complex object during program initialization instead on configuration time.
You already use Spring and it is easy construct DataSource by:
<context:property-placeholder location="classpath:app.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#${db.host}:${db.port}:${db.user}"/>
<property name="username" value="${db.user}"/>
<property name="password" value="${db.pass}"/>
</bean>
I completely agree with Ralph with using deployment descriptor in $CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xmlbut instead JNDI I like plain key-value file!
With Spring injecting above properties into bean fields are easy:
#Value("${db.user}") String defaultSchema;
instead of JNDI:
#Inject ApplicationContext context;
Enviroment env = context.getEnvironment();
String defaultSchema = env.getProperty("db.user");
Note also that EL allow this (default values and deep recursive substitution):
#Value('${db.user:testdb}') private String dbUserName;
<property name='username' value='${db.user.${env}}'/>
To externalize .properties file I use modern Tomcat 7 that has org.apache.catalina.loader.VirtualWebappLoader:
<Loader className="org.apache.catalina.loader.VirtualWebappLoader"
virtualClasspath="/srv/web/app/"/>
So your devops fill virtualClasspath with local external full paths which is separate per application and put local app.propertiesto that dir.
See also:
Adding a directory to tomcat classpath
Can I create a custom classpath on a per application basis in Tomcat
Externalizing Tomcat webapp config from .war file
How to read a properties file outside my webapp context in Tomcat
Configure Tomcat to use properties file to load DB connection information
Externalize Tomcat configuration
step 1: context.xml
<Context path="/projectname">
<Resource auth="Container"
driverClassName="com.mysql.jdbc.Driver"
logAbandoned="true"
maxActive="100" ``
maxIdle="30"
maxWait="10000"
name="refname"
removeAbandoned="true"
removeAbandonedTimeout="60"
type="javax.sql.DataSource"
url="jdbc:mysql://localhost:8080/dbname"
username="root"
password="root"/>
</Context>
Step 2 : web.xml
<resource-ref>
<description>DB Connection</description>
<res-ref-name>refname</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Step 3 : create a class to get connection
Connection connection = null;
Context context = (Context) new InitialContext().lookup("java:comp/env");
DataSource ds = (DataSource) context.lookup("refname");
connection = ds.getConnection();
Everything is set
You also can use JNDI URL support for different application configuration for test, integration test, production.
<Context>
...
<Resource auth="Container" factory="com.benasmussen.jndi.url.URLFactory"
name="url/MyUrl" type="java.net.URL" url="file:///your/path/to/file"/>
...
</Context>
<jee:jndi-lookup id="myUrl" jndi-name="java:comp/env/url/MyUrl" expected-type="java.net.URL" />
Check out the GitHub project Tomcat JNDI URL Support to enable JNDI URL support for Tomcat servers.