You edited a Tomcat application's settings in webapps/myapp/META-INF/context.xml, and the change vanished the next time the WAR was deployed. Where does Tomcat look for a Context descriptor, which location survives redeployment, and what do the Host attributes deployXML and copyXML control?
answer
- exploded directory is build output
- per-host conf directory outranks the WAR
- one attribute ignores packaged descriptors
- descriptor file names follow WAR naming
basics
~20 sRedeploying a WAR deletes and recreates the exploded directory, taking your edit with it. The descriptor that survives is conf/<engine>/<host>/<appname>.xml, which also wins over the copy packaged in the WAR. deployXML decides whether packaged descriptors are honoured at all; copyXML copies one out at deployment.
solid answer
~40 sAnything under `webapps/myapp/` is derived from the archive: on redeploy Tomcat deletes that directory and re-expands the WAR, so edits there are always temporary. Tomcat merges Context settings from several places — `conf/context.xml` for every application, `conf/<engine>/<host>/context.xml.default` for one host, the application's own `/META-INF/context.xml`, and `conf/<engine>/<host>/<appname>.xml`, which is the deployment descriptor Tomcat itself manages and which takes precedence. Putting your `<Resource>` or `docBase` there keeps it across redeploys, and the file is named by the same rules as the WAR: `ROOT.xml`, `shop#eu.xml`, `shop##002.xml`. `copyXML="true"` makes Tomcat copy the packaged `META-INF/context.xml` into that directory on first deployment; `deployXML="false"` makes it ignore packaged descriptors entirely, which is a hardening measure because a descriptor can set privileged things like `docBase` outside the application base.
code
xml · 10 lines<!-- $CATALINA_BASE/conf/Catalina/localhost/myapp.xml : survives redeploy -->
<Context docBase="/srv/releases/myapp-4.2.1.war" reloadable="false">
<Resource name="jdbc/orders"
auth="Container"
type="javax.sql.DataSource"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://db.internal:5432/orders"
username="orders_app"
password="REPLACED_AT_DEPLOY"/>
</Context>go deeper
Know that the exploded webapps/<app>/ directory is regenerated from the WAR on every deployment, so configuration edited there does not last.
List the four places Tomcat reads Context settings from and their precedence, and say what copyXML and deployXML change about the packaged descriptor.
Design the deployment layout: artifact identical across environments, environment configuration in the per-host descriptor or outside Tomcat, docBase pointing at a release directory, reloadable off.
Decide the trust boundary — whether application teams may ship their own context descriptors at all, given that one can define datasources, valves and a docBase outside the application base.
## What a Context descriptor is A `<Context>` element configures one deployed web application: its `docBase`, whether it is `reloadable`, its `<Resource>` JNDI entries, its `<Manager>`, `<Loader>`, `<Valve>` elements, cookie settings, and so on. It is Tomcat's own configuration, distinct from `WEB-INF/web.xml`, which is the portable Servlet-specification deployment descriptor for servlets, filters and mappings. ## Every place Tomcat reads one from In increasing order of specificity, Tomcat combines: 1. **`$CATALINA_BASE/conf/context.xml`** — defaults applied to every application in the instance. 2. **`$CATALINA_BASE/conf/<engine>/<host>/context.xml.default`** — defaults for one virtual host, e.g. `conf/Catalina/localhost/context.xml.default`. 3. **`/META-INF/context.xml` inside the application** — shipped with the WAR by its developers. 4. **`$CATALINA_BASE/conf/<engine>/<host>/<appname>.xml`** — the per-application descriptor, e.g. `conf/Catalina/localhost/myapp.xml`. This is the authoritative one and it is what the Manager application writes when you deploy through it. The file in (4) is named with the same encoding as WAR files: `ROOT.xml` for the root context, `shop#eu.xml` for `/shop/eu`, `shop##002.xml` for a versioned deployment. ## Why your edit disappeared `webapps/myapp/` is not a source of truth — it is the expansion of `myapp.war`. When `autoDeploy` sees a newer WAR (or when you redeploy through the Manager), Tomcat undeploys the context, **deletes the exploded directory** and the matching directory under `work/`, then unpacks the archive again. Everything you hand-edited inside it, including `META-INF/context.xml`, is regenerated from the archive. The same applies to `WEB-INF/classes` tweaks and to files an application wrote into its own directory. The durable options are: put the setting in `conf/<engine>/<host>/<appname>.xml`, or put it in the WAR at build time so the next artifact carries it. ## copyXML and deployXML Two `<Host>` attributes decide how packaged descriptors are treated: - **`copyXML`** (default `false`): when `true`, Tomcat copies the application's `/META-INF/context.xml` to `conf/<engine>/<host>/<appname>.xml` at deployment time. From then on the copy is what is read — so later changes inside the WAR are ignored until that file is removed, which surprises people who expect the packaged file to keep winning. - **`deployXML`** (default `true`): when `false`, Tomcat ignores `/META-INF/context.xml` entirely. This matters in shared hosting, because a context descriptor can set `docBase` to a path outside `appBase`, add `<Valve>`s and `<Resource>`s, and otherwise reach beyond the application. Turning it off means only the administrator, editing `conf/<engine>/<host>/`, can configure a context. ```xml <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" deployXML="false" copyXML="false"> </Host> ``` ## Attributes worth knowing on the element itself - **`docBase`** — the application's content directory or WAR. Setting it in `conf/<engine>/<host>/<appname>.xml` lets you serve an application from *outside* `appBase`, which is the standard way to keep releases out of Tomcat's own directory tree. Pointing `docBase` at a location inside `appBase` while also having the WAR there causes double deployment and confusing duplicate contexts. - **`path`** — legal only when the `<Context>` is nested in `server.xml`; otherwise the path comes from the file name and the attribute is ignored. - **`reloadable`** — Tomcat watches `WEB-INF/classes` and `WEB-INF/lib` and restarts the context when a class file changes. Useful in development, expensive in production (constant scanning, plus a full context restart with a fresh class loader on every change), and the documentation says to leave it off in production. - **`<Resource>` and `<ResourceLink>`** — the application's JNDI entries; the descriptor is the natural home for credentials you do not want inside the artifact. ## The practical rule Treat the deployed directory as build output and the `conf/<engine>/<host>/` descriptor as configuration. Anything environment-specific — datasource URLs, credentials, `docBase` locations — belongs in the descriptor (or an environment mechanism outside Tomcat), because the artifact should be identical between staging and production while its configuration is not.
- What is the difference between context.xml and WEB-INF/web.xml?`web.xml` is the portable Servlet deployment descriptor — servlets, filters, listeners, URL mappings, session config — and any compliant container reads it. `context.xml` is Tomcat-specific configuration *about* the deployed application: docBase, reloadable, JNDI `<Resource>` definitions, valves, the session manager. Moving to another container means rewriting the context descriptor, not the web.xml.
- Why would an administrator set deployXML="false" on a Host?Because a packaged context descriptor is privileged configuration written by whoever built the WAR: it can point `docBase` outside the application base, install valves, and define JNDI resources. On a host where applications are deployed by less-trusted parties, ignoring packaged descriptors means only the administrator's files under `conf/<engine>/<host>/` can configure a context.
- Why is reloadable="true" discouraged in production?Tomcat has to poll `WEB-INF/classes` and `WEB-INF/lib` continuously, and any change restarts the whole context with a new class loader — dropping in-memory state and adding one more loader for the JVM to reclaim. It is a development convenience; in production you deploy a new artifact and, ideally, restart the JVM instead.
saying these in an interview costs you the question
- Editing files in the exploded directory as configuration
- Thinking META-INF/context.xml always wins
- Confusing context.xml with WEB-INF/web.xml
- Leaving reloadable="true" on in production
- Believing the descriptor can choose the context path