carehart / awesome-cf-compose

A repository of Docker Compose examples for use with the ColdFusion images from Adobe, Lucee, and Ortus
Creative Commons Zero v1.0 Universal
46 stars 11 forks source link

Possible to change /app to be /app/wwwroot? #2

Open bennadel opened 2 years ago

bennadel commented 2 years ago

I've been looking through existing Docker resources for ACF and trying Google, but I can't find anything. My issue is that Adobe ColdFusion seems to mount /app as the web root; but, what I need is for it to mount /app/wwwroot as the web root. The reason for this being that I have stuff outside my web root that is loaded/read-in at run time. In other words, not all of the files for my site intended to be web-accessible.

When I was trying to use Ortus' CommandBox image, they have a special ENV for this, APP_DIR. From the docs:

APP_DIR - Application directory (web root). By default, this is /app. If you are deploying an application with mappings outside of the root, you would want to provide this environment variable to point to the webroot ( e.g. /app/wwwroot )

Does the ACF image have anything equivalent?

I was poking around in the ACF container and I see there is a CF setup script that contains what looks like the mapping:

updateWebroot(){

        echo "Updating webroot to /app"
        xmlstarlet ed -P -S -L -s /Server/Service/Engine/Host -t elem -n ContextHolder -v "" \
                -i //ContextHolder -t attr -n "path" -v "" \
                -i //ContextHolder -t attr -n "docBase" -v "/app" \
                -i //ContextHolder -t attr -n "WorkDir" -v "/opt/coldfusion/cfusion/runtime/conf/Catalina/localhost/tmp" \
                -r //ContextHolder -v Context \
        /opt/coldfusion/cfusion/runtime/conf/server.xml

# .....

... so I thought maybe that we being written to an XML file that I could overwrite, but can't seem to find a mention of /app anywhere.

carehart commented 2 years ago

Hey, Ben. I have good news: a couple of options, actually.

First some background: to be clear, that capability is not currently provided for by the ACF images, no. As you note, the issue is simply that that startup file doesn't provide for modifying that underlying server.xml file to set a new docbase attribute for the context element, which is the way one would set the webroot folder path for the internal Tomcat web server. And that's of course the built-in web server for both CF and the CF images.

1) So one solution would indeed be to provide for modifying that, and an env var is a good way to do it. And for that to work, of course that startup script would have to provide for it. And that's the first good news I can share. I have created a variant of that script, /opt/startup/start-coldfusion.sh. It's based on the version of that file from the CF2021.0.5 image (so I have not checked it against earlier CF2021 or 2018 images).

I have attached that here. Well, Github does not permit me offering an sh, so I renamed it to .txt.: start-coldfusion.txt. After saving and renaming back to an .sh and putting it in the built directory for your Dockerfile, you could then copy that into the image with the COPY command in that Dockerfile.

In that startup script, I provide simply for an optional webroot env var, which defaults to the traditional /app. You could set it with the ENV directive in the Dockerfile to instead be /app/wwwroot. I have confirmed it works, creating that dir and setting that as the web server's webroot. Let me know how it goes for you, and I'll put together a sample Dockerfile demonstrating it.

2) A second solution would be to look at the problem differently: I suspect most people using CF would NOT go about modifying that server.xml file and the default context's docbase. :-) What do they do instead? Well, they use an external web server (typically IIS or Apache), and then they use THAT to set the webroot instead--which is the webroot for THAT web server, and then CF runs whatever the web server tells it, wherever it finds it.

So that would be another solution to this problem you propose. Maybe you (like many folks) have been stumped trying to setup either of those web servers (and their AJP connector) with the CF images. It's not impossible, but it's neither easy nor necessarily the way to go.

Instead, web servers like nginx are far more popular in containers--and that can be set to proxypass a request to that internal web server for execution. I have an example of that here on the site.

  1. Finally, I was working up a different example for someone who wanted their CF mapping for a subfolder to be the root. In doing that, I also created another nginx example, where one port uses the /app folder as its root, while another port uses an /app/app1 folder as its root. The latter is closer to what you are asking about. I'd like to evolve an example that is more clearly solving the problem you pose, but it's at least simple enough for you to take the ball an run with it until then. That's in /cf-nginx-app_in_subfolder.

Let me know if either of these work well for you, and I'll improve things further based on that.

bennadel commented 2 years ago

This is awesome Charlie, thank you! Trying it now :)

bennadel commented 2 years ago

Woot woot!! It worked 💪 This is the Dockerfile I am running:

FROM adobecoldfusion/coldfusion2021:2021.0.5

# Overwrite the startup script with a modified version that uses an ENV to define the
# server's app-root.
COPY ./opt/startup/start-coldfusion.sh /opt/startup/start-coldfusion.sh

# Copy latest compatible MySQL Connector/J to fix LocalDateTime casting issue.
COPY ./lib/mysql-connector-java-8.0.22.jar /opt/coldfusion/cfusion/lib/

And then here's what I have in my docker-compose.yml file:

  cfml:
    build: "./build/cfml"
    ports:
      - "8500:8500"
    environment:
      acceptEULA: "YES"
      password: "password"
      webroot: "/app/wwwroot"
      installModules: "mail,image,debugger"
    volumes:
     - "../bennadel.com:/app"
    depends_on:
      mysql:
        condition: service_healthy
    healthcheck:
      test: "echo hello"

So now:

After being dead in the water (locally) for days, my site finally popped right up! (Well, after like 2-mins of startup time). So exciting. I'm slowly beginning to understand how some of this works. I actually did try looking at the server.xml file after the boot-up to see if I could find where /app was being stored ... thinking I could COPY over a modified server.xml file. But, alas, I could not find any mention of /app anywhere. I even tried running:

find -r './' -e '/app\b'

... in various folder and couldn't find any matches at all 🤷 so, not sure where that configuration is actually ending up. I think I might try to take a course on Tomcat on Udemy - I know basically nothing about how the underlying Java server actually works, and I think that's a huge missing part of my ability to do anything beyond writing CFML code.

bennadel commented 2 years ago

Also, I didn't understand what you are saying about nginx. I do have nginx running in a container; but, it doesn't have any notion of the webroot - it just proxy-passes to the cfml container in the network:

    location ~ (\.cfm|\.cfml|\.cfc)(.*)$ {
        proxy_pass  http://cfml:8500;
        include     inc_lucee-proxy.conf;
    }

... the mention of "lucee" here is because I copied it over from some Lucee CommandBox example. nginx is another thing that I barely know anything about, so it's a lot of copy-pasta.

carehart commented 1 year ago

Hey, Ben. I see I never replied to this. So sorry.

As for your last question, you wonder how to solve this problem with nginx, which "doesn't have any notion of the web root [when] it just proxy-passes to the cfml container".

I get the sense that you may have missed the last point I was making, specifically addressing that, in my previous reply. So I've just edited that to give a number that point as "3" there. It just didn't stand out clearly from the point 2.

I realize that by now you may have moved on from the whole discussion. If so, let me know and I can close the issue. Or if you have may more to say related to the topic here, I'd welcome it.

bennadel commented 8 months ago

Circling back to this after a year 😆 thank you for the clarity on the nginx stuff. I think I see what you are saying now. I'm currently trying to figure out how to test the 2021-Update-13 locally before updating in production. But, I'm currently on CommandBox's image and apparently they aren't even using Tomcat. I might try again with the ACF image using your nginx-based sub-folder routing notion. Thanks again!

carehart commented 8 months ago

Yep, they use undertow instead (for various technical reasons), but you could have nginx forward/proxypass to its internal web server just like CF's, sure. Or yep, set things up to work with CF's for when something doesn't seem to work with their (Ortus/Commandbox) CF images but you want to see if it will using Adobe's.