CommandBox and Port 80 and Port 443

Hi, I am a 20+ year CFML developer and I’d like to use CommandBox as an Ubuntu service to host a public web server for my site. I am trying to set up CommandBox for the first time, but am getting the errors around Port 80 and Port 443 being unavailable, since we’re not running CommandBox with a root user.

I have seen a few answers online to this, and none of them seem to make sense to me. Some of them, frankly, seem ludicrous:

  1. Just run as a root user
    Well, this goes against every security principle I’ve ever learned. Why do we feel this is acceptable when everything I see everywhere on the internet strongly recommends against it?

  2. Put in an Apache or Nginx reverse proxy
    So, isn’t the whole point of CommandBox, here, to avoid having to deal with the unbelievably painstaking, insanely and extraordinarily frustrating hassle of doing a reverse proxy?

  3. Use iptables or authbind
    This seems really hacky and full of risk, too.

I’ve looked into why Apache and Nginx, which, you know, also don’t run as root users, are able to bind to these ports. Apparently they start up in root and then lower their privileges after they bind the ports. Is this not possible in CommandBox?

I honestly have read just about everything I can find on Google related to CommandBox, Lucee, Port 80 and so on. I’m not seeing answers here. Perhaps this thread can help me and the rest of the world understand more about this issue?

I don’t know of any other ways to do it. The limitation of non-root users not being able to bind to ports below 1024 is hard-code into Unix systems. I’m not sure how CommandBox would bind as a root user and then lower permissions from Java, but I’m open to suggestions on what that would look like.

It doesn’t seem that hacky and I’m not aware of any risk right off. Can you enlighten me? I’ve always regarded this as the “right” answer if you don’t want to run as root, which is understandable.

2 Likes

Firstly, no? CommandBox is not a replacement for a reverse proxy… though it can replace a reverse proxy setup, that’s not its primary purpose. I believe most hosted Ortus services use CommandBox and a reverse proxy in tandem for a secure, highly configurable environment.

Secondly, I feel like you’re dramatically overstating the difficulty of a reverse proxy setup. The amount of research you’ve done into *nix port permissions would have sufficed to get you a solid reverse proxy by now. It’s certainly much easier to set up a reverse proxy than it is to hack around the unix permissions architecture.

I’ve looked into why Apache and Nginx, which, you know, also don’t run as root users, are able to bind to these ports. Apparently they start up in root and then lower their privileges after they bind the ports.

So they start up as root, and you conclude that they don’t run as root? I admit I know very little about this, but I’m reading Nginx uses a root process and a non-root process. So you will never be able to listen to port 80 or 443 in Nginx without starting the nginx master/root process (probably a daemon?) as root.

2 Likes

@GoOutside I’m not sure what your experience level is with reverse proxies, but these are very easy to achieve when using something like NGINX. See below. This is all there is to it if you want to proxy incoming traffic for port 80 to 8888 instead:

upstream app_server {
    keepalive 10;	
    keepalive_timeout 60s;
    keepalive_requests 100;
    hash $remote_addr consistent;
    server localhost:8888;
}

server {
    listen 80;
    server_name yourdomain.com;

    location / {
        # Set a long timeout so that first requests don't 504
        proxy_connect_timeout       1800;
        proxy_send_timeout          1800;
        proxy_read_timeout          1800;
        send_timeout                1800;
        proxy_http_version 1.1;
        proxy_pass http://app_server;
    }
}

2 Likes

So I spent some time Googling this again, which I had done a few years ago and I hit the same dead ends.

  • “not recommended”
  • “not secure”
  • “can’t be done in Java”
  • “requires very low level linux distro-specific native commands”

ChatGPT tried and tried to talk me out of even thinking about it, lol. So, I don’t really know exactly how Nginx, or Apache accomplish this, but I’m all ears if you have experience with how to do it with Java. I have a feeling they have some sort of wrapper shell script they use to actually start the server as root, then somehow detect when the ports are bound, and then capture the PID of the process and use sudo to modify the process. I really couldn’t get clear instructions and I don’t know if the commands are even the same across Linux distros. Google and ChatGPT just kept telling me it was a terrible idea, and was “insecure” and “not recommended” :person_shrugging:

I wouldn’t use the phrase “whole point of”, but yes IMO one of the primary purposes of CommandBox is to simplify your server setup, and with the Multi-site features in ComandBox 6, to be able to become the web server component as well so you don’t need a reverse proxy. Most people doing CommandBox in production though to be real honest are

  • on Windows
  • on Docker

so the port binding is either not an issue, or they already have some ingress proxy setup (or they just run Docker as root since it’s already sandboxed). One might think it would be more of a problem that a process can’t bind to port 80 on Linux without using root, but I probably only get this question once every few years so it’s something the vast majority of CFer’s on CommandBox have worked around without issue.

Why am I trying to avoid reverse proxy?

I’ve run a Lucee server on an AWS Lightsail instance for 7+ years. It was set up with the old, no-longer-developed ubuntu-nginx-lucee scripts, which were very helpful. It was extremely stable and would run for months without even slight issues.

Due to end-of-life issues with the Ubuntu and Nginx setup, I had to move to a new server. Since ubuntu-nginx-lucee was no longer working, I tried connecting through reverse proxy with Apache. Nothing about my code has changed. The version of Lucee I’m using was the same as before. The only difference is the version of Ubuntu and that I am now using Apache. I installed via the last known “installer” that was available on download.lucee.org

The server is now so unstable that it completely crashes about every 2-3 hours, intermittently. The opaqueness of these crashes, alone, is frustrating, but most the issues seem to point to challenges in the way mod_cfml (which seems to somehow be the most widely used AND poorly documented component of Lucee) is managing the relationship between Lucee and Apache2.

That is why I am trying to avoid reverse proxy. The reverse proxy is causing within two months an entire lifetime of headaches that I’ve never experienced before, which is causing me to want to find the absolute most straightforward, simplest possible server setup I can find.

“Try running Lucee without Apache, then!” There are zero resources on how to do this. Zero. I can not find a single guide on how to manage this kind of a set up. Maybe I’m missing one?

That’s why I turned to CommandBox, the system that is spoken about with such reverential awe across the Lucee ecosystem. While there is more documentation for CommandBox than perhaps even Lucee, itself, it’s still pretty light when it comes to set-up. I continue to struggle to find a straightforward guide on how to set up a standalone, simple, public-facing Lucee server. (And I’m talking about basic things like, "in what directory do you download CommandBox? From what directory do you first run CommandBox? Do you run it with sudo? Where are the configuration files? Do they move? How do we run it as a service on a headless cloud instance? Do we create a new unix user to run it? What should be the permissions of the webroot directory that you’re trying to serve .cfm pages from? An earlier question I had in another thread: how do I even get into the web administrator? These issues around unix users, permissions, configuration, location of files, etc. … they are extremely hard to understand, partly because there is so little guidance on them, and lots of conflicting forum posts about them.)

If one can use CommandBox and Nginx as the reverse proxy but not have to deal with the insanely frustrating issues of memory leaks and network problems that seem to accompany the Apache2/Mod_cfml/Lucee setup that’s currently limping along for me, then that might be helpful. Nginx, alone, is probably fine. But if mod_cfml enters the picture, things suddenly seem to get complicated beyond a point where I can do anything about it.

Last note: I am a hobbyist, not a professional developer. I do not have a budget for expensive support options. I do not have an infrastructure team to ask to support me. I don’t have colleagues I can ask for help. I’m alone, trying to figure this out on my own. This was really not that hard for the last seven years. Something has happened recently that’s somehow made this much, much harder.

FWIW, if you are using Lightsail, there’s no need to bind to port 80 or 443. You can just add the http ( 8080 ) and https (8443) ports in the deployment configuration and the domain will resolve on Port 80 or 443 to your running CommandBox instance.

The AWS load balancer for your deployment listens on the standard HTTP ports and then forwards to the lightsail deployment port

2 Likes

I’d rather you use CommandBox without a reverse proxy because I just love CommandBox that much, but I must say I think you’re throwing the baby out with the bathwater. Most of the Linux-hosted-Lucee community use mod_cfml without issue and there’s got to be something on your end. Your issue may not even be related to Modcfml at all. If you don’t have resources to pay for support, I understand that, but I’d try posting about your issues in the Lucee forum which is pretty active and see if you can get to the bottom of it without just throwing out the tech you seem so familiar with.

Sure there are, your problem is you’re asking the wrong question,. Lucee is not a web server and does not contain a web server, so Lucee doesn’t have docs on how to configure a web server since… it isn’t one. Now, there are a myriad of web servers out there you can use Lucee with (each with their own docs), but it’s up to you to

  • choose a web server
  • read that web server’s docs

Sure, it would be nice if Lucee had prebuilt guides for every single possible web server out there it could be used with, but Lucee does not have Adobe’s budget and costs you $0.00 so you get what you get.

The Lucee installer bundles Apache Tomcat for your convenience. You can find the docs for configuring Tomcat’s HTTP listener here:
https://tomcat.apache.org/tomcat-5.5-doc/config/http.html
Note these docs are on Apache’s site, because the web server is a feature of Tomcat, not Lucee.

That’s fair, but mostly because CommandBox doesn’t care how you set it up. It’s an exe and you do whatever the heck you please with it. Honestly, we don’t care. Do what you will.

Wherever you want. CommandBox does not require it to be downloaded in any particular folder. It’s just a stand alone exe, after all.

Wherever you want. CommandBox doesn’t care where you run it from any more than git, or docker care.

Only if you want it to run as root. But again that’s up to you.

Which ones? CommandBox itself has but one config file and it’s not documented because it’s an implementation detail that you don’t need to know about. But, for the record, it’s in the CommandBox home directory called CommandBox.json.
Now, there are use config files you can create such as server.json for a particular server, but if you haven’t guessed-- it can go really whereever you want to put it. Docs here.

I don’t really know what this means. No, I mean not on their own. They don’t, like, have legs or anything :slight_smile:

Depends on what you mean by “cloud”. If it’s Docker, then the Docker daemon is the service. If it’s just Windows or Lightsail, then you create a service in accordance to that operating system’s documentation. We have a module you can buy for like 50 bucks that does it for you on Mac, Linux and Windows. https://commandbox-service-manager.ortusbooks.com/

Sure, if you want. Up to you.

Read by whatever user the process is running as-- unless you’re application write to it. But that’s sort of just common sense, right?

The same way you do from any Lucee server. /lucee/admin/server.cfm CommandBox does nothing to change that-- Lucee controls that URL.
CommandBox does also offer for your convenience:

  • a try icon for GUI operating systems with an “Open” > “Server admin” and “Web admin” menu item you can click on
  • the server open --admin command if you’re running CommandBox in a desktop

I don’t get what’s hard to understand. The reason you see different information is because everyone has their own way of doing things. Not everyone agrees on how the best setup is for a server.

These issues appear to be specific to you, not general to the setup. I’m not aware of anyone else having these issues.

mod cfml does add another layer of complexity, but if you have more than one website/webroot you’re pretty much going to have to use mod cfml (or CommandBox 6’s multi-site feature which is basically our baked in version of mod cfml). But either way, there’s going to be a learning curve you can’t get around.

I understand it can be frustrating when you just want to find a guide that tells you exactly what to do, but then you come across a tool that is generic and usable in many ways that leaves more decisions to you. Adobe CF always did a “good” job of abstracting all those decisions away from you so it “just worked” but Lucee is more of a tinker platform where you’ll find more people who want to tune their carburetors and swap out a custom exhaust and the tooling here presents more flexibility to do so at the expense of not necessarily just being a “push button start”.

I would recommend starting some targeted threads looking for help/clarification on specific things you need help understanding. You’ve asked a lot of questions here, but more than can really be answered without getting confusing.

These instructions apply to the Lightsail Container service, which I am not using (nor even know how to use, as it seems pretty overkill in terms of both cost and complexity for a simple CFML web server). I am working from a Lightsail instance of Ubuntu 20/22, sort of similar in concept to AWS EC2, which costs about $10 a month.

I need the web server to be able to do FTP hosting, file management, image processing, S3 integrations and MySQL database hosting, so containers doesn’t really seem that useful to me? And a lot more expensive? It seems like the simple Lightstail Instance at $10 is kind of a good deal for a hobbyist with a low-traffic site. Should I be looking at something else?

I need the web server to be able to do FTP hosting, file management, image processing, S3 integrations and MySQL database hosting,

If you are adding additional server dependencies for all of these things above, then I would just suggest installing NGINX, popping the config @gcopley gave you above in to the config directory for nginx and calling it a day.

Thank you, @jclausen and @gcopley. I’ve added an nginx server and used your configuration, @gcopley, and it seems to be working. I’ll next need to work on SSL forwarding for port 443. Hopefully that will be easy but I’ll let you know if I have trouble.

@gcopley, I’m a bit confused on how I would configure nginx/lucee/commandbox to handle port 443 connections. Specifically, I’d like to include a 301 redirect for all port 80 requests to port 443? (And, of course, everything would be pushed along to Lucee.)

The only method I’m aware of includes all of the junk from mod_cfml, which isn’t the most helpful stuff on the planet.

@GoOutside You don’t need to make any changes to Lucee or CommandBox. You just need to add the SSL configuration for your site for port 443 in your Nginx configuration and proxy to port 8080 like you do for port 80.

You can add your 301 redirect there also. I’ll send you an example here in a bit. Typing from my phone currently.

Thank you, @gcopley. Would it be appropriate, then, to put this redirect line into the server {} block for port 80, to force all :80 connections over to :443?

server {
    listen 80 default_server
    ....
    # Redirect all HTTP requests to HTTPS
    return 301 https://$host$request_uri;
    ....
}

And then continue with the port 443 server {} block>

The reason I ask this is because I get this weird feeling that these kinds of redirects can be at the root of some of the weirdness I get in webroots, web contexts, etc. (and largely I think that’s from weirdness within mod_cfml, which I’d very much prefer to never touch again in my life).

Well, if you want to have an automatic redirect that detects HTTP traffic and bounces them back over to HTTPS, you need a little more than just the port proxying. The Nginx example Grant showed is one way to do it, You can also detect that scenario in your CF code, or CommandBox actually has a setting that does that for you (redirects).

server set web.SSL.forceSSLRedirect=true

HOWEVER, in order for that to work, CommandBox needs to know what was SSL which usually involves setting a header in your Nginx config for scheme or secure or something. CommandBox looks for the X-Forwarded-Proto header to determine if an upstream proxy (Nginx in this case) terminated the SSL connection.

proxy_set_header X-Forwarded-Proto https;

@GoOutside Here you go. I’ve added comments to walk you through it.

# We define a proxy, and we give it a name of 'app_server'.
upstream app_server {
    keepalive 10;	
    keepalive_timeout 60s;
    keepalive_requests 100;
    hash $remote_addr consistent;
    server localhost:8888;
}

# We create a port 80 server definition that does
# nothing but 301 redirects the user.
server {
    listen 80;
    return 301 https://$host$request_uri;
}

# We create a port 443 server definition that does 
# the hard work.
server {
    listen 443 ssl;
    server_name yourdomain.com;

    # We tell NGINX where our SSL certificate files are
    ssl_certificate /full/path/to/yourdomain.crt;
    ssl_certificate_key /full/path/to/yourdomain.key;
    server_name_in_redirect off;

    # We funnel all requests to our proxy named 'app_server', 
    # which runs on port 8888. 
    location / {

        # We set our proxy parameters
        proxy_pass http://app_server;
        proxy_connect_timeout       1800;
        proxy_send_timeout          1800;
        proxy_read_timeout          1800;
        send_timeout                1800;
        proxy_http_version 1.1;

        # If we need to set additional headers that get
        # passed by the proxy, we can here.
        #
        # proxy_redirect off;
        # proxy_set_header Host $host;
        # proxy_set_header X-Forwarded-Host $host;
        # proxy_set_header X-Forwarded-Server $host;
        # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # proxy_set_header X-Real-IP $remote_addr;
    }

}

Thank you very much, @gcopley, this is very interesting. One thing I’m wondering, in other lucee/nginx configurations, I see things like this in a lucee.conf file:

location ~* (\.cfm(\/|$)|\.cfc$) {
  include lucee-proxy.conf;
}

which then points to something like this in lucee-proxy.conf:

proxy_pass http://127.0.0.1:8888;
#include standard proxy headers
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
#populate the cgi.https variable with on or off based on map condition which must be specified in a http {} block
proxy_set_header https $cgi_https;

proxy_set_header X-Tomcat-DocRoot $document_root;
proxy_set_header X-ModCFML-SharedKey secretkey;

if ($lucee_context = false) {
        set $lucee_context $document_root;
}
proxy_set_header X-Webserver-Context $lucee_context;

# Enable path_info - http://www.lucee.nl/post.cfm/enable-path-info-on-nginx-with-lucee-and-railo
set $pathinfo "";
# if the extension .cfm or .cfc is found, followed by a slash and optional extra
if ($uri ~ "^(.+?\.cf[mc])(/.*)") {
    # remember the filepath without path_info
    set $script $1;
    set $pathinfo $2;
    # rewrite the url to match the filepath wthout path_info
    rewrite ^.+$ $script break;
}
# set the custom path_info header
proxy_set_header XAJP-PATH-INFO $pathinfo;

I’m curious why other Nginx/Lucee configurations seem to do something like this, and whether this is all just redundant fluff, or why it’s there? I’m guessing it’s to “catch” all .cfm pages requests so they’re processed through Lucee. But … doesn’t Lucee already do that?

I guess I’m saying, your configuration seems almost too simple to be true! Why is there this big amount of extra configuration present in so many other examples around the internet?

It looks like they are setting some additional headers, probably for Tomcat to support multiple sites on a single Lucee installation. Also, they are only proxying URLs that end in .cfm or .cfc. That means some requests are proxying to Lucee while other requests are being served by NGINX directly. It’s one of several ways to go about things, and as you pointed out, a bit messy.

In the configuration I sent you, we proxy everything to CommandBox and let it take over from there.

Long story short, IMO it’s a bunch of fluff and complexity we don’t need in our lives anymore. :slight_smile:

With this setup, things are much easier. Let’s block access to the Lucee admin for example.

  location ~* /lucee/ {
    # allow 10.0.0.1; # Add your IP address here
    deny all; # block access
  }
1 Like