tomcat
tomcat copied to clipboard
running as non-root: Unable to create directory for deployment: [/usr/local/tomcat/conf/Catalina/localhost]
When running as non-root, I'm getting the following error in the log:
Unable to create directory for deployment: [/usr/local/tomcat/conf/Catalina/localhost]
As this directory is not part of the Tomcat distribution, tomcat tries to create it itself, but if you're running as non-root, Tomcat won't have the privileges to do so.
No Linux guru myself I wonder if this fixable in the dockerfiles provided here, as it seems to entail giving write/execute permissions to all parent folders for the user used to run Tomcat and allowing that user modification access to the /conf folder looks to me to be not so desirable
Also not sure how dynamic those folder names (Catelina and localhost) are
I think it's an innocuous error? We have seen this error a few times https://github.com/docker-library/tomcat/issues/35 https://github.com/docker-library/tomcat/issues/128#issuecomment-411636133
Comparing the hosted webpage for root and non-root they both give a 404 (due to no webapps https://github.com/docker-library/tomcat/pull/181)
$ docker run -d --rm --name tomcat -p 8080:8080 --user 1000:1000 tomcat
361e2ed8409e7331cb6eb85fe97eef734ab31f6df4763ccdecffba84867bcbf0
$ docker run -d --rm --name tomcat1 -p 8081:8080 tomcat
3c564babae2cbfc245e920edf03642514632f04f4889d172ee18ab9f89df84ed
$ diff -s <(curl localhost:8080 2>/dev/null) <(curl localhost:8081 2>/dev/null)
Files /dev/fd/63 and /dev/fd/62 are identical
But trying to get the webapps enabled from a Dockerfile to test a non-404 page I'm getting a weird error
Testing
$ docker build -t tomcat:webapps - << EOF
FROM tomcat
RUN cp -a $CATALINA_HOME/webapps.dist/manager $CATALINA_HOME/webapps/manager
EOF
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM tomcat
---> 2ae23eb477aa
Step 2/2 : RUN cp -a /webapps.dist/manager /webapps/manager
---> Running in c69d88ccd97a
cp: cannot stat '/webapps.dist/manager': No such file or directory
The command '/bin/sh -c cp -a /webapps.dist/manager /webapps/manager' returned a non-zero code: 1
Running that layer as a container and doing it from an exec
works though
$ docker inspect c69d88ccd97a | grep sha
"Image": "sha256:2ae23eb477aa82782438e429f22e551c1a093e2aebb804fb3d1463dd510c16cb",
"Image": "sha256:2ae23eb477aa82782438e429f22e551c1a093e2aebb804fb3d1463dd510c16cb",
$ docker run -it --rm sha256:2ae23eb477aa82782438e429f22e551c1a093e2aebb804fb3d1463dd510c16cb bash
root@7915537f8b27:/usr/local/tomcat# cp -avT $CATALINA_HOME/webapps.dist/manager $CATALINA_HOME/webapps/manager
'/usr/local/tomcat/webapps.dist/manager/images/asf-logo.svg' -> '/usr/local/tomcat/webapps/manager/images/asf-logo.svg'
'/usr/local/tomcat/webapps.dist/manager/images/tomcat.gif' -> '/usr/local/tomcat/webapps/manager/images/tomcat.gif'
'/usr/local/tomcat/webapps.dist/manager/index.jsp' -> '/usr/local/tomcat/webapps/manager/index.jsp'
'/usr/local/tomcat/webapps.dist/manager/status.xsd' -> '/usr/local/tomcat/webapps/manager/status.xsd'
'/usr/local/tomcat/webapps.dist/manager/xform.xsl' -> '/usr/local/tomcat/webapps/manager/xform.xsl'
'/usr/local/tomcat/webapps.dist/manager/META-INF/context.xml' -> '/usr/local/tomcat/webapps/manager/META-INF/context.xml'
'/usr/local/tomcat/webapps.dist/manager/WEB-INF/jsp/401.jsp' -> '/usr/local/tomcat/webapps/manager/WEB-INF/jsp/401.jsp'
'/usr/local/tomcat/webapps.dist/manager/WEB-INF/jsp/403.jsp' -> '/usr/local/tomcat/webapps/manager/WEB-INF/jsp/403.jsp'
'/usr/local/tomcat/webapps.dist/manager/WEB-INF/jsp/404.jsp' -> '/usr/local/tomcat/webapps/manager/WEB-INF/jsp/404.jsp'
'/usr/local/tomcat/webapps.dist/manager/WEB-INF/jsp/connectorCerts.jsp' -> '/usr/local/tomcat/webapps/manager/WEB-INF/jsp/connectorCerts.jsp'
'/usr/local/tomcat/webapps.dist/manager/WEB-INF/jsp/connectorCiphers.jsp' -> '/usr/local/tomcat/webapps/manager/WEB-INF/jsp/connectorCiphers.jsp'
'/usr/local/tomcat/webapps.dist/manager/WEB-INF/jsp/connectorTrustedCerts.jsp' -> '/usr/local/tomcat/webapps/manager/WEB-INF/jsp/connectorTrustedCerts.jsp'
'/usr/local/tomcat/webapps.dist/manager/WEB-INF/jsp/sessionDetail.jsp' -> '/usr/local/tomcat/webapps/manager/WEB-INF/jsp/sessionDetail.jsp'
'/usr/local/tomcat/webapps.dist/manager/WEB-INF/jsp/sessionsList.jsp' -> '/usr/local/tomcat/webapps/manager/WEB-INF/jsp/sessionsList.jsp'
'/usr/local/tomcat/webapps.dist/manager/WEB-INF/web.xml' -> '/usr/local/tomcat/webapps/manager/WEB-INF/web.xml'
So testing with an image a few months after the PR allowing for running as an arbitrary user https://github.com/docker-library/tomcat/pull/129 (Sep 10, 2018, and has the webapps enabled by default) Image used from Dec 13, 2018 https://github.com/docker-library/repo-info/blob/d2b4f29618bc1dec9361e88ebf731b6ead196242/repos/tomcat/remote/9.0-jre8.md
One with --user
, one without
$ docker run -d --rm --name tomcat3 -p 8083:8080 tomcat@sha256:0a276681ea3785f008057d7e7a9861d5e934dbaea725a9bfd429fe26afb36e18
512361859c76458ea95493fbffbf8d6a7ca8fd3929eb7a59b5a5e7010150a953
$ docker run -d --rm --name tomcat4 -p 8084:8080 --user 1000:1000 tomcat@sha256:0a276681ea3785f008057d7e7a9861d5e934dbaea725a9bfd429fe26afb36e18
52c6793e49d0e7f1903be7bd9b8ee8e8f41f78c5703c4fdaeb13354e99882905
The error message is present on the one running as an arbitrary user
$ docker logs tomcat3 2>&1 | grep -i unable
$ docker logs tomcat4 2>&1 | grep -i unable
27-Aug-2020 15:19:39.299 SEVERE [main] org.apache.catalina.startup.HostConfig.beforeStart Unable to create directory for deployment: [/usr/local/tomcat/conf/Catalina/localhost]
But they appear identical when testing the hosted webpage
$ diff -s <(curl localhost:8083 2>/dev/null) <(curl localhost:8084 2>/dev/null)
Files /dev/fd/63 and /dev/fd/62 are identical
$ curl -i localhost:8083 2>/dev/null | head -n 1
HTTP/1.1 200
$ curl -i localhost:8084 2>/dev/null | head -n 1
HTTP/1.1 200
$ curl -v localhost:8083 2>/dev/null | head -n 20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Apache Tomcat/9.0.14</title>
<link href="favicon.ico" rel="icon" type="image/x-icon" />
<link href="favicon.ico" rel="shortcut icon" type="image/x-icon" />
<link href="tomcat.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="wrapper">
<div id="navigation" class="curved container">
<span id="nav-home"><a href="https://tomcat.apache.org/">Home</a></span>
<span id="nav-hosts"><a href="/docs/">Documentation</a></span>
<span id="nav-config"><a href="/docs/config/">Configuration</a></span>
<span id="nav-examples"><a href="/examples/">Examples</a></span>
afaik (not being a Tomcat expert here), the /conf/Catalina/localhost directory is for storing context.xml files, but as far as I found, it would be the administrator doing that BEFORE launching Tomcat.
However, Tomcat seems to (try to) create the directory on startup, so I assume Tomcat has a need for that directory to exist. Why create it otherwise?
So what could happen somewhere down the line if it failed to create it on startup?
I did find you can turn of the creation of these directories using the createDirs attribute on the host tag in server.xml, but what this means down the line I could not find.
I tried to create this directory while building docker-image with my app and set a+rwx permissions to the new create directory.
RUN mkdir -p /usr/local/tomcat/conf/Catalina/localhost
RUN chmod -R a+rwx /usr/local/tomcat/conf/Catalina
Container is starting without any errors with non root user, but the 8080 proto is not working, and i have no clues why
After starting I see following log entries, no other errors
07-Dec-2020 15:48:05.855 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
07-Dec-2020 15:48:05.867 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [328] milliseconds
07-Dec-2020 15:53:49.844 INFO [Thread-4] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"]
07-Dec-2020 15:53:49.851 INFO [Thread-4] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina]
07-Dec-2020 15:53:49.870 INFO [Thread-4] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"]
07-Dec-2020 15:53:49.903 INFO [Thread-4] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
I'm using tomcat:9.0.38-jdk8-corretto
https://tomcat.apache.org/tomcat-9.0-doc/config/host.html
server.xml declares Host
s inside Engine
. A host will have a xml configuration created under xmlBase
, which by default is $CATALINA_BASE/conf/<engine_name>/<host_name>
.
If you want to avoid tomcat trying to create this directory, you can set createDirs
to false.
If set to true, Tomcat will attempt to create the directories defined by the attributes appBase and xmlBase during the startup phase. The default value is true. If set to true, and directory creation fails, an error message will be printed out but will not halt the startup sequence.
I tried to create this directory while building docker-image with my app and set a+rwx permissions to the new create directory.
RUN mkdir -p /usr/local/tomcat/conf/Catalina/localhost RUN chmod -R a+rwx /usr/local/tomcat/conf/Catalina
Container is starting without any errors with non root user, but the 8080 proto is not working, and i have no clues why
After starting I see following log entries, no other errors
07-Dec-2020 15:48:05.855 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"] 07-Dec-2020 15:48:05.867 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [328] milliseconds 07-Dec-2020 15:53:49.844 INFO [Thread-4] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"] 07-Dec-2020 15:53:49.851 INFO [Thread-4] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina] 07-Dec-2020 15:53:49.870 INFO [Thread-4] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"] 07-Dec-2020 15:53:49.903 INFO [Thread-4] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
I'm using tomcat:9.0.38-jdk8-corretto
This will obviously make the container start without the SEVERE error. But I don't think it's the best solution, we didn't find the root of the problem.