Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

running as non-root: Unable to create directory for deployment: [/usr/local/tomcat/conf/Catalina/localhost] #209

Open
p-bakker opened this issue Aug 27, 2020 · 7 comments

Comments

@p-bakker
Copy link

p-bakker commented Aug 27, 2020

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

@wglambert
Copy link

I think it's an innocuous error? We have seen this error a few times #35 #128 (comment)

Comparing the hosted webpage for root and non-root they both give a 404 (due to no webapps #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 #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>

@p-bakker
Copy link
Author

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.

@gropox
Copy link

gropox commented Dec 7, 2020

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

@bendem
Copy link

bendem commented Aug 22, 2022

https://tomcat.apache.org/tomcat-9.0-doc/config/host.html

server.xml declares Hosts 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.

@FueledBy-Pizza
Copy link

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.

@ddjuric1
Copy link

ddjuric1 commented Nov 30, 2024

The tomcat user (I'm talking about version tomcat-9.0.x) should definitely be allowed to create the ./Catalina/localhost path.
That's why in Linux (Debian 12 in my case) we need to do

chmod 777 ./conf

while in the $CATALINA_HOME path (in my case it was /opt/tomcat9).
After that, copy $CATALINA_HOME/webapps/{appname}/META-INF/context.xml to ./Catalina/localhost/{appname}.xml ,
reboot or restart tomcat and tomcat will no longer change the content of it, and will use options from that file.

Regards

@LaurentGoderre
Copy link
Member

LaurentGoderre commented Dec 12, 2024

An easy way around this issue is to use a named volume.

docker run -d --rm \
  --name tomcat
  -v conf:/usr/local/tomcat/conf/Catalina/localhost \
  -p 8080:8080 \
  --user 1000:1000 \
  tomcat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants