Deploying Java webapp to Tomcat 8 running in Docker container
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Deploying a Java web application to Tomcat 8 in Docker usually means building a WAR file and placing it inside a Tomcat image under webapps. The container gives you a repeatable runtime, while Tomcat still handles the servlet lifecycle exactly as it would on a normal server.
Build the WAR First
Most Tomcat deployments start with a WAR artifact. With Maven, the package step is straightforward:
If the build succeeds, you should get a file such as:
That WAR is what Tomcat deploys. Docker is packaging the runtime around it, not replacing the WAR deployment model.
A Simple Dockerfile
Use the official Tomcat image and copy the WAR into webapps:
Then build the image:
And run it:
Tomcat will unpack and deploy the WAR automatically when the container starts.
Deploy at the Root Context
If you want the application at / instead of /myapp, rename the WAR to ROOT.war:
That is often cleaner for single-application containers.
Multi-Stage Build for Cleaner Images
If you do not want Maven inside the runtime image, use a multi-stage build:
This keeps the final image smaller and avoids shipping build tooling into production.
Logs and Troubleshooting
If the app does not start, check Tomcat's logs inside the container:
Or open a shell:
Useful things to inspect:
- The WAR file exists in
webapps - The file name matches the intended context path
- Tomcat started without servlet or classpath errors
- The application is actually listening on port
8080
Environment and Configuration
Containers work best when environment-specific settings are passed from the outside rather than baked into the WAR. For example:
This keeps the same image reusable across test, staging, and production.
Development Versus Production Images
During local development, teams sometimes mount the WAR or exploded webapp into the container as a volume so they can iterate quickly. That can be useful, but it is different from a production image. In production, you usually want an immutable image with one exact WAR baked in so deployments are repeatable and easy to trace.
Tomcat Context Path and File Names
Tomcat derives the default context path from the WAR file name. That means:
- '
myapp.warbecomes/myapp' - '
ROOT.warbecomes/'
This rule explains many "the container is up but my route is 404" issues. The application may be running correctly, but at a different context path than expected.
Common Pitfalls
- Copying the WAR to the wrong Tomcat directory.
- Forgetting that the WAR file name controls the default context path.
- Debugging Docker networking when the real failure is inside Tomcat startup logs.
- Building a huge runtime image by shipping Maven and source code into production unnecessarily.
Summary
- Build a WAR, then copy it into a Tomcat 8 image under
webapps. - Use
ROOT.warif you want the app served at the root path. - Multi-stage Docker builds keep the runtime image cleaner.
- Check
docker logsfirst when deployment fails. - Docker standardizes the runtime, but Tomcat deployment rules still apply.

