Tomcat rollback after a failed upgrade: symlink switch or in-place reinstall — what are the limits?
0 reputation · 31 Aug 2025, 20:10 UTC
0 reputation · 31 Aug 2025, 20:10 UTC
We maintain several Tomcat 9 instances and are planning a move to Tomcat 10.1. Using the documented CATALINA_HOME/CATALINA_BASE split, our binaries live in versioned directories while conf/, logs/, and webapps/ sit in a separate CATALINA_BASE, so in theory a failed upgrade should be recoverable without touching instance configuration.
The unresolved decision is the rollback mechanism itself. One option is keeping the previous Tomcat directory intact and repointing a symlink (and the systemd unit's CATALINA_HOME) back to the old release. The other is reinstalling the old version in place over the failed one. Each seems to have different implications for systemd unit definitions, file permissions, and our audit trail of which binary served which deployment.
We also know the jakarta.* namespace migration means rollback must include redeploying the original javax.* WARs, and that work/ and temp/ caches are version-specific.
Does the symlink approach have any documented limits when systemd units hardcode paths? Is reinstalling in place ever preferable for auditability? And must expanded WAR directories be cleared on rollback, or only the JSP compilation cache?
31275 reputation · 01 Sept 2025, 06:34 UTC
With a proper CATALINA_HOME/CATALINA_BASE split, the symlink switch is the preferred rollback method unless your systemd unit hardcodes the versioned directory. In‑place reinstall does not improve auditability and carries the risk of leaving orphaned files. On rollback you must redeploy the original javax.* WARs and clear the entire work/ and temp/ directories—not just the JSP cache.
The symlink itself poses no Tomcat‑side limit; Tomcat resolves CATALINA_HOME at startup regardless of whether it is a link. The only operational limit comes from how the systemd unit references that path:
Environment=CATALINA_HOME=/opt/tomcat-current (or an EnvironmentFile with that variable), changing the symlink target requires only systemctl restart tomcat./opt/tomcat-10.1.30, every rollback forces you to edit the unit and run systemctl daemon-reload before restarting.Thus the documented limit is self‑inflicted: hardcoded paths break the zero‑downtime advantage of symlinks.
Reinstalling the old version over the failed one is rarely preferable. It does not give a clearer audit trail because the versioned directory is overwritten, erasing evidence of which binary served a given deployment. It also risks leaving stray JARs from the failed upgrade on the classpath, which can cause subtle linkage errors. Only consider an in‑place reinstall if you cannot keep the old versioned directory (e.g., severe disk‑space constraints) and you accept the extra verification steps to ensure a clean classpath.
$CATALINA_BASE/webapps/ (and the webapps-javaee/ folder if the migration feature was used).$CATALINA_BASE/work/ directory; it holds compiled JSP classes and other version‑specific artifacts that can cause ClassCastException if stale.$CATALINA_BASE/temp/ for the same reason.# Confirm symlink points to the intended version
ls -l /opt/tomcat-current
# Verify the running JVM sees the correct CATALINA_HOME
ps -ef | grep catalina.home
# Ensure work/ and temp/ are empty before restart
ls $CATALINA_BASE/work
ls $CATALINA_BASE/temp
# Check that a known‑good javax.* WAR is serving requests
curl -s http://localhost:8080/your-app/healthOne missing diagnostic detail that would change the recommendation: does your systemd unit define CATALINA_HOME via an Environment variable (or EnvironmentFile) or does it hardcode the versioned path? If it hardcodes, you must update the unit and run systemctl daemon-reload before each rollback.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.