[Solved] Lucee/lucee:5.3-nginx: listen tcp4 0.0.0.0:443: bind: address already in use

lucee/lucee:5.3-nginx
OS: Ubuntu 20.04 on a Digital Ocean droplet
Lucee Version: 5.3.9.141

Hi. I am pretty new to VMs (Digital Ocean) and Docker, and might be misunderstanding how the ports work.

The DNS for flowt.com.au is hosted on my ISP (VentraIP in Australia).
I have a subdomain there apiv1.flowt.com.au which resolves to the IP address of my Digital Ocean droplet.

I configured nginx and ran certbot according to the very helpful instructions at DO. According to those instructions, the recommended method was to create a separate site and associated nginx server block for that subdomain.

Without my docker containers, as a basic test, I can browse to https://apiv1.flowt.com.au/ and I see my default index.html page which serves from /var/www/apiv1.flowt.com.au/html/index.html
So far so good.

Now… I have an initial test docker compose file pulling in mariadb and my custom Lucee image.
The image was built FROM lucee/lucee:5.3-nginx, pushed to DockerHub then pulled in.

My compose ports are as follows (the full file is below)

    ports:
    - "80:80"
    - "443:443"

Everything was working on port 80 before I installed the SSL. In other words I was using the default nginx web setup and I could browse to http://apiv1.flowt.com.au/ and see my test index.cfm page which dumped a cfquery served by the Lucee container. All correct.

I removed the containers and am now trying to compose them so I can browse to https://apiv1.flowt.com.au/ and see my default index.html page there, ie the same as pre-HTTPS. Once that works I will then try to get my index.cfm page (served by Lucee) working.

However…
The problem: when I do the docker compose I now get:
ERROR: for 35d69e2b733e_flowt_lucee_1 Cannot start service lucee: driver failed programming external connectivity on endpoint flowt_lucee_1 (c4e13f08ebf19196352715309a5179e939700e9189aaaa01f359c84445fffb4a): Error starting userland proxy: listen tcp4 0.0.0.0:443: bind: address already in use

Doing
#sudo netstat -pna | grep 443 yields:
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 24768/nginx: master tcp6 0 0 :::443 :::* LISTEN 24768/nginx: master

I tried with a defined bridge network in case the default one was the culprit. Same result.

Can anyone shed some light please?

Here is my complete compose file. It is just for a test db and passwords etc.

version: "3"

networks:
  mynetwork:
    driver: bridge

services:
  db:
    image: mariadb:latest

    volumes:
      - ./mariadb-data:/var/lib/mysql
    restart: always
    environment:
      MARIADB_ROOT_PASSWORD: mypass

    networks:
      - mynetwork

    ports:
      - '3306:3306'

  lucee:
    depends_on:
      - db
    image: murrahdock/lucee-site-1:latest
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD : mypass
      MYSQL_HOST : db
      MYSQL_DATABASE : test

    networks:
      - mynetwork

    ports:
    - "80:80"
    - "443:443"

Thanks,
Murray

Murray, this is confirming that you have nginx already running–NOT as a container, and it’s listening on 443. So you can’t then fire up the lucee/nginx container and have it ALSO listen in port 443.

You have many options, depending on your goals:

  • you could stop the nginx running on its own, and then you WOULD be able to run your lucee container
  • you could expose the port in the container instead as another port, like 444–but then someone would have to know that to use it, which might be clumsy
  • you could instead keep nginx running on its own, serving port 443, but have it PROXY requests to Lucee, like that port 80…but you probably also would find nginx to be listening on that, so you’d still have a conflict. But you could change the compose file to use just 81:80, and have the real nginx proxy to that. You can Google to find many discussions of having nginx proxy/forward requests to some backend like this.
  • and so on

Let us know if that helps. If not,. I’m sure many others will have still other ideas and responses for you.

Thanks for your speedy reply @carehart, much appreciated.

Ok, I am beginning to understand (I hope).

I think I need to keep the nginx that is running on the vm Ubuntu host (not in a container) because it is managing the SSL certificate for apiv1.flowt.com.au.

Therefore, it sounds like I should:

  1. leave the host vm nginx running so it handles the SSL cert on the domain apiv1.flowt.com.au`
  2. compose the Lucee container as say 81:80 (doesn’t need 443 because nginx has handled that?)
  3. set up a proxy on the host vm nginx that says
    “any traffic to port apiv1.flowt.com.au:443 should be directed to apiv1.flowt.com.au:81”
    which Lucee is listening on.

Am I understanding an approach here?

Thanks again,
Murray

What I understand is, that you are running ngnix twice: one in your docker container (comming from your docker image) and another outside running in your VM (that you installed using the DO instructions). You won’t be able to run both on the same port.

I have no experience with docker, but from my point of view, you need to get rid of one of those instances: Or make your SSL work (including certificate renovation) purely on your dockers ngnix, or use a docker Lucee container without ngnix, but using the VMs ngnix server then as frontend. Running both in parallel wouldn’t make much sense, because it would consume more ressources than you’d need.

Thanks @andreas - yes, I have been busy exploring this and the doubling up occurred to me while I was implementing the solution. Thanks for confirming my suspicion. :slight_smile:

Re: the double nginx:
In my Dockerfile I presume I can simply use FROM lucee/lucee:5.3 instead of FROM lucee/lucee:5.3-nginx now and let Tomcat handle the traffic. I will try that.

Re: the SSL issue:
So, I want the vm nginx so the SSL on the domain is managed and also much much later I can use it for other redirecting, load balancing, etc.

Therefore what I did was to run the docker compose with Lucee ports mapped as:
ports:
- “81:80”

ie dropped mapping port 443 altogether and host 81 maps to container 80.

Then I amended my /etc/nginx/sites-available/apiv1.flowt.com.au file to use the
proxy_pass http://localhost:81;
plus I added some comments so I remember what this all means next time!

Included here for others who might be similarly confused - never having seen nginx config before!

server {
    # This is the 443 HTTPS block

    root /var/www/apiv1.flowt.com.au/html;
    index index.html index.htm index.cfm index.nginx-debian.html;

    server_name apiv1.flowt.com.au www.apiv1.flowt.com.au;

    location / {
        # I removed this:
        #    try_files $uri $uri/ =404;

        # I added this line to forward the requests on port 443 (SSL) to port 81
        # on localhost which is what the Lucee container is listening on
        # because in your docker compose you set port 81:80
        # ie host port 81 maps to container port 80
        proxy_pass http://localhost:81;
    }

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/apiv1.flowt.com.au/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/apiv1.flowt.com.au/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
    # This is the 80 HTTP block

    # This block says: if any traffic comes in on port 80 (http:) for
    # either ipv4 or ipv6,
    # for any of the domain names listed in `server_name` below,
    # redirect via the 301 to the `https` server
    # which the server block above will handle.

    if ($host = www.apiv1.flowt.com.au) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = apiv1.flowt.com.au) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    listen [::]:80;

    server_name apiv1.flowt.com.au www.apiv1.flowt.com.au;
    return 404; # managed by Certbot
}

And it works! Yay!

And… it is obvious now! LOL :wink:

Thanks so much to @carehart and @andreas for your help.
Best wishes,
Murray

1 Like

PS: These are the helpful Digital Ocean tutorials about SSL certificates, nginx and certbot.

https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-20-04

https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-20-04

1 Like

Yep, Murray, there you go. That’s exactly what I was getting at by my 3rd option. I figured that’s what you wanted but you needed to confirm. :slight_smile: Good on ya for sharing the final nginx config, and yep on no longer needing the nginx version of the Lucee image.

And glad you found those and shared DO articles on nginx. They do indeed have SO many helpful ones, on so many topics, but sadly they can’t spell Coldfusion (or Lucee). OK, it’s supply and demand (and you may want to consider offering even a basic one on your effort here, as many of us could–myself included).

I wanted to share one more learning resource you may want to consider, as you embark on your journey to cfml in Docker: the InLeague “CF Swarm” guide.

Before I do, let me take just a moment of preface to note that since you’re currently using the Lucee-provided images, you’ll want to be aware also of the Ortus Commandbox Docker images. They’re different from the native Lucee ones (and native Adobe CF ones), in ways that many find helpful. Even so, many are also happy using just the native ones.

But back to your road to learning more about Docker–and specifically cfml on Docker, I want to briefly highlight the substantial CF Swarm guide, at https://cfswarm.inleague.io/.

Started some years ago by Samuel Knowlton and the folks at InLeague, the guide is an ambitious intro to containers for cf devs and admins. While it has a clear focus on Lucee, most of the info offered could help one getting started with deploying cfml on ACF as well.

Indeed, despite the guide having Swarm in its name, the guide is useful even to those NOT using Docker Swarm (which, though it has lost in the race for dominant container orchestration platforms, is still favored by some).

The guide starts out showing use the Ortus Commandbox images, and for deployment it shows use of Digital Ocean. It later also shows building your own image, which some favor doing. (It eschews showing or using the Adobe-provided CF images, because of Adobe’s licensing model which is so poorly suited to container deployment, though it acknowledges that it is free for and works well in development.)

Most parts the guide have not been updated in some years, but what has been done can still be very useful for many. It covers a number of topics, some in considerable depth.

And several topics are incomplete, having section heads with no content–like roads planned but never paved. But stretching that analogy, those exit ramps at least point you in a good direction where often your own further exploration can get you where you need to go. :slight_smile:

The guide is open source, so of course contributions would seem welcome by the organizers.

2 Likes

@carehart Thanks again Charlie. Yes, I am putting a bit of a how-to together - once I have it all working! :wink:

Re: CF Swarm guide. Well… that’s a hidden gem. In all my googling that never showed up. Maybe there is a link on the Lucee docs that I also missed? Anyway, I will read with interest.

Go well,
Murray

Done: https://lucee.daemonite.io/t/tutorial-lucee-docker-and-vscode-in-2022/10857
:slight_smile:

1 Like

Thanks for the heads up, and for the effort itself. If you may get feedback and/or build it out, perhaps you could then offer it to DO as a tutorial. That would certainly increase the chance of folks finding what you’ve done here.

Or again, perhaps someone else (or I) may get motivated to do that at some point. It would certainly help in bringing attention to cf/lucee from outside our current community/ies.

But none of that diminishes the value of what you (and others) have done so far on the topic.