Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Traditional CommandBox servers have only a single web root and if you want to start up two separate sites, then you start two CommandBox servers which creates two separate Java processes. This may be cumbersome or even untenable if you have hundreds site separate sites you want to run as the overhead of the JVMs would require too much memory.
CommandBox can also use a popular standard called ModCFML which allows it to behave like an Adobe ColdFusion Tomcat-based installation, which you can set behind a web server and CF will pull the webroots dynamically from the web server, allowing any number of separate sites to all be run on a single JVM instance.
ModCFML takes it's name from the convention of Apache modules, which are named mod_xyz
and is really more of a standard implemented by several different libraries. The way ModCFML works, is the front-end web server (IIS, Apache, Nginx, etc) passes a few custom HTTP headers to the back end CF server on each request that tells the CF server where the web root lives for that site. Here's an overview of the related libraries:
BonCode - Boncode is an AJP proxy for IIS which can be configured globally or on a per-site basis to proxy requests to a back-end CF server. Boncode automatically sends the ModCFML HTTP headers. Docs here.
Apache mod_cfml module - This module can be installed into Apache HTTPd server to create an AJP reverse proxy. Docs here.
Tomcat ModCFML Valve - This Tomcat valve creates contexts in Tomcat for the incoming ModCFML Headers. Since you're using CommandBox, you don't need this since CommandBox has support for the equivalent behavior built in!
CommandBox - CommandBox will obey the standard ModCFML HTTP headers so long as ModCFML.enable
is set to true
for the server.
Nginx or other web servers - Even though there is no native ModCFML module for Nginx, you can still use it by just setting the necessary HTTP headers manually! More on this below.
This is the minimum needed to configure ModCFML for any front-end web server in CommandBox:
That's it! The default web root for the server will be whatever folder you start the CommandBox sever in, but that default web root will only be used if a requests reaches CommandBox which doesn't contain the special ModCFML HTTP headers.
Next you'll need to install BonCode (if using IIS) or mod_cfml (if using Apache) and configure it with the same shared key for security. The web server doesn't need to be on the same server as CommandBox, but CommandBox's AJP port does need to be accessible to the web server and the port numbers need to match. 8009 is the default AJP port, but it's not a requirement.
Here are some additional ModCFML settings you may want to tweak:
This limits the number of contexts which can be created to prevent a malicious client from causing a DOS from a huge number of contexts, which would eventually begin consuming memory. Default is 200
.
Set this to false
FOR DEVELOPMENT PURPOSES ONLY to not require the shared key header to be present. This may simplify your local setup, but do NOT enable this on any externally-accessible web server as a malicious client could send their own HTTP headers and serve content from anywhere on your server's hard drive! Default is true
.
Here are some settings you may be familiar with in the Tomcat valve, that CommandBox does NOT use.
CommandBox does NOT have a corresponding setting for timeBetweenContexts
**** since Undertow is VERY fast to add new contexts.
CommandBox does NOT have a corresponding setting for scanClassPaths
**** because it re-uses the existing class loader and cloned Undertow deployment from the default context so no jars at all need to be scanned.
CommandBox does NOT have a corresponding setting for loggingEnabled
. There is already logging as part of Runwar and the --debug
flag when you start your server will automatically log additional bits.
CommandBox does NOT have a corresponding setting for responseCode
**** because it is capable of adding the new context entirely on the fly and using it immediately without needing to re-send the request.
You can use any front end web server you like so long as you manually set the HTTP headers that ModCFML requires. Here they are:
X-ModCFML-SharedKey
- Needs to match the ModCFML.sharedKey
in your server.json
X-Tomcat-DocRoot
- Needs to contain the absolute path to the web root for the current virtual host
X-Webserver-Context
- Optional. Will be used instead of hostname to group multiple hostnames into a single context
X-VDirs
- A string representing the aliases (virtual directories) of the web server for CommandBox to auto-create in the servlet in the format: /foo,C:\path\to\foo;/bar,C:\path\to\bar
X-VDirs-SharedKey
- Must also contain the same value as X-ModCFML-SharedKey
or X-VDirs
will be ignored. This is for security since the older mod_cfml Apache proxies don't override a missing X-VDir
header, allowing malicious client to pass one. Only pass the X-VDirs-SharedKey
header if your proxy is explicitly controlling the contents of the X-VDirs
header.
For NGinx, setting the headers would look like this and would need configured for each site.
It is not required to use an AJP proxy. CommandBox's ModCFML support will process the incoming HTTP headers regardless of what protocol was used to proxy the requests to it.
How do you confirm ModCFML is working or debug when it doesn't go right? CommandBox has automatic debug
and trace
level messages that will appear in the console when you start your server with the --debug
or --trace
flag that will tell you when a new context is deployed and what the web root is.
CommandBox's ModCFML support will work for both Adobe and Lucee servers! Keep in mind however, that Lucee and Adobe work differently under the covers, even though it looks the same from the outside. When the server is Lucee, CommandBox's ModCFML support will create a new servlet context deployment for each web context. Each servlet context will have a context root of /
and will share the same class loader as the default instance, so they will also share the same server context. Adobe only uses the default servlet context, but swaps out the resource manager per-request, just like Adobe's Tomcat-based installations work. If you don't know what all that means, don't worry.
As of CommandBox 6.0, this no longer works as the server rules have been moved back AFTER the ModCFML logic. But don't fret, Multi-Site mode now gives you this capability and much much more.
You maybe wondering if it's possible to make use of multiple web roots in CommandBox without having any web server at all. Well, we weren't going to let you in on this, but actually YES it is possible! All you need to do is configure some Server Rules to detect the host name and set the HTTP headers and CommandBox's ModCFML will be none the wiser. You can turn off the requirement of a shared key, but make sure you have a catch-all rule that rejects requests from unknown host names.
Here is the server.json
for a simple setup. Note, we're using the commandbox-hostupdater
module here to auto-create hosts
file mappings for our domains. We're also pointing the webroots to site1.com
, site2.com
, and site3.com
folders inside of the default web root, but these could really point anywhere you like.
If you want something SUPER quick and dirty for local development and you TRUST the people accessing the site, you could get really clever and just have a simple convention where the host name matches a a folder inside of your default web root. Any hostnames that didn't match a real folder would just use the default web root.
Adjust HTTP, SSL or AJP bindings per site using CommandBox Multi-Site
HTTP bindings are much more robust in Multi-Site mode. In single-site mode, there is basically no such thing as host name bindings. All traffic coming into that CommandBox server is simply routed to the one and only server regardless of its host name or IP address.
This page covers bindings from a Multi-Site perspective, but the general docs on all Binding options is here.
As of version 6.0, a CommandBox server can now have
Any number of HTTP bindings on any IP/port combination
Any number of SSL bindings on any IP/port combination
Any number of AJP bindings on any IP/port combination
And furthermore, a binding can be shared for all sites on the server, or could serve traffic to ONLY a single site depending on how you configure it. Think how IIS, Nginx or Apache work. You now have the same level of flexibility in CommandBox!
CommandBox 6 has introduced a new syntax for bindings (and is still backwards compatible with the old JSON syntax too) that allows you to specify hostnames alongside the bindings:
Even though each site can use a different IP/port, a very common setup is to have a single port 80
/443
binding at the server level shared by all sites, and then simply specify a hostname for each site. If you only need to specify a host name for a site, but don't need to declare a new binding (because you're inheriting a binding from the global level) then you can use the new hostAlias
key at the site level which can be a list or array of hostnames to be layered on top of the global bindings for this site:
In Multisite mode, each site can have as many bindings as you want, where each binding has:
An IP address (or all IPs, which is the equivalent to 0.0.0.0
)
A port
Zero or more hostnames
Exact (full) match like www.foo.com
Starts-with match like *.foo.com
or *bar.com
Ends-with match like www.foo.*
or www.bar*
Regular expression match like ~www\.(bob|tom|bernard)Industries\.(com|net|org)
When a request comes into CommandBox in multi-site mode, the most specific binding will be found, and the traffic served to the matching site. The order of precedence of binding matching is as follows:
Exact IP and hostname match
Exact IP and hostname ends with match
Exact IP and hostname starts with match
Exact IP and hostname regex match
Any IP and hostname exact match
Any IP and hostname ends with match
Any IP and hostname starts with match
Any IP and hostname regex match
Try Exact IP and any hostname
Any IP and any hostname
Default site
If you need help debugging how your bindings are being assembled at runtime, you can use this command:
which will show you all the listeners (ports/IPs) that CommandBox is listening to at the OS level as well as all the bindings for each site that control what listeners will map to them:
If you do not specify any bindings at all, it will still pick a random port to bind to. It will also pick a SEPARATE random port for each site so you can access each site separately.
Each site can have a default open browser URL, but CommandBox will not automatically open a browser in Multi-Site mode. These URLs will be available in a sub menu of the tray icon, or can be used from the server open
command like so:
If no bindings were matched, then CommandBox will look for a default site configuration. Unlike IIS which has a default site created by scratch, or Apache which just takes the first site defined, CommandBox requires you to explicitly define a default site like Nginx. If no default site is defined, CommandBox has a built in "site not found" error page that will be shown. You can avoid or "turn off" this default page by setting a default site.
Configure any of your sites to be the default site by adding a default
key set to true
inside the site JSON. It doesn't matter whether the site is defined in the server.json
in the sites
object or in an external site JSON file.
Learn how to serve multiple sites with different web roots, rewrites, and more from a single CommandBox server
The default behavior when you run server start
is to start a server that points only to a single web root. There are two methods you can use to host more than one web root at a time in a single CommandBox server:
ModCFML- this requires a web server sitting in front of CommandBox which sends special HTTP headers that instruct CommandBox what to use as the web root.
Multi-Site mode- this is new in CommandBox 6.0 and it allows full configuration of multiple sites (web roots), rewrite, HTTP/SSL bindings, and settings inside of a single server.
In both cases, there is a single JVM process and a single CF Engine at play. So all sites will use the same CF engine and version. If you want to run different versions of CF, you'll need more than one server. You can use a reverse proxy in your server rules to still access all your sites via a single "front end" server instance.
The CommandBox built-in web server is now fully fledged with out-of-the-box support for multiple bindings, host header matching, multiple SSL certs/SNI, and full control over rewrites gzip compression, virtual directories (aliases) and secure profiles on a per-site basis. CommandBox is now truly the only tool you need to deploy your code! There's no need to have Apache, IIS, or Nginx in the mix any longer.
There is a repo on Github that contains working examples of all the features of Multi-Site. Feel free to skip straight there to learn by example.
https://github.com/Ortus-Solutions/commandbox-tests
You are free to use CommandBox as you wish for development purposes, but if you are using more than 2 sites in production, we ask you consider supporting us with a CommandBox Pro license which bundles support and commercial modules and extensions.
Please note that the legacy form of rewrites using Tuckey will NOT work by default in Multi-Site mode. There are two main reasons for this limitation:
Tuckey is tied to the servlet and static files are now no longer served by the Default Servlet, but are returned to the browser without even touching the servlet.
There is only one servlet servicing all sites, so you can't have different rewrites per site.
Not ready to leave Tuckey? You can force the new Undertow web server to not serve static files by setting servletPassPredicate=true
, which will send ALL files to the servlet:
Read more about the servlet pass predicate here.
However, the best approach is to simply switch over to using Server Rules. They do everything Tuckey does, AND each site can get its own separate set of server rules for maximum configurability.
Also note, when you set this flag:
as of CommandBox 6, a Tuckey XML rewrite file will no longer be employed. Instead Server Rules will be added that perform the same rewrites as the old Tuckey functionality. Tuckey will now ONLY be used if you specify a custom rewrite file.
Use a servlet pass predicate to define which requests should be forwarded to the servlet
In a traditional server setup, you are used to two separate pieces of software
A web server like NGinx, Apache, or IIS which serves static files, performs URL rewrites, and proxies some requests off to a servlet
A Servlet container like Tomcat or CommandBox receiving the proxied requests on another port (HTTP or AJP) and processing CF code
In CommandBox, now we have the ability to combine both of those bullets together into a single piece of software. No reverse proxy is needed, nor is a second port to proxy to.
In all cases with the legacy setup, there is always a check of some kind that decides which requests will get sent to the servlet. This is usually checking for URLs ending in .cfm
or .cfc
. Common implementations of this are:
Adobe's CF connector
The mod_cfml module for Apache
BonCode for IIS
A custom proxy directive in your web server.
As of CommandBox 6, we have the same setting and it can be set as web.servletPassPredicate
which is simply an Undertow Predicate. By default, CommandBox uses the following predicate for the servletPassPredicate
:
So the URI /index.cfm
will get sent to the servlet, but /test.txt
would just get sent by the static file resource handler. You can customize this if necessary with any valid Undertow predicate. It can even be different on a per-site basis by setting it inside the sites
object or .site.json
file for a given site.
Note, be careful as your servlet pass setting may send .cfm
files to the static file handler. CommandBox has a failsafe in place to prevent the source code from being returned, but you should still use caution when configuring this.
Defining sites in CommandBox Multi-Site
There's no flag or setting for enabling multiple sites in a single server. All you have to do is
define a sites
object in server.json
or a siteConfigFiles
setting in server.json
inside your server.json
and if one or more sites are found, CommandBox will automatically switch over to "Multi-Site" mode. It's easy to tell if a server has more than one site. When you start it, the console output will have a dedicated section in the output for each site. There is also additional information in the server info
command about each site.
Let's explore the two methods of defining more sites.
The sites
object will have a key for each site you want to define where the name of the key is the name of each site and the value is another object containing the configuration of that site. Think of all of the setting which can be set in the web
object of server.json
. Each site object in the sites
object can have all the same settings as the top-level web
object so it will be very familiar.
The simple example server.json
above, some defaults that apply to all sites are defined in the top-level web
object. Then we have two sites, site1
and site2
defined with their own settings. Remember, each site object is just a copy of the web
object above, so all the same settings are valid. You can use the server set
command to configure these and rely on the tab completion to help prompt you with all valid options.
The ONLY required settings for each site are
webroot
or siteConfigFile
which points to a JSON file on disk where a web root must be defined
If you want to access each site individually, you'll either want to specify a separate HTTP/SSL/AJP binding OR a custom hostname for each site. Otherwise, you'll have no way to access them!
You can also place a .site.json
file inside of the web root, which will be found by convention and its contents will be added to the site object for that site. This is akin to configuring your sites in Apache, but having an .htaccess
file in each web root to override settings.
System setting expansions will be processed in any .site.json
files, and if a .env
file exists in the web root as well, thoses env vars will be loaded, but JUST for that .site.json
file's expansions.
siteConfigFiles
setting in server.json
If you have a lot of sites, or a lot of settings, the first option can become unwieldly since the server.json
will have a lot of stuff in it. That is why we also allow you to specify a siteConfigFiles
setting which contains a list or array of file globbing patterns or directories to look for JSON files in. Once all the JSON files have been found, they will be used to define sites. each JSON file will contain JUST the contents of the object you would have put in the sites
object of server.json
which has all the same options as a web
object in server.json
.
Valid examples could be:
System setting expansions will be processed in any of the site JSON files located via your file globbing patterns. If the server.json
has a sites
object AND a siteConfigFiles
setting, all sites will be combined together. Feel free to choose the approach that fits your needs!
Learn how (and where) to configure multiple sites from a single CommandBox server
As soon as CommandBox flips over to Multi-Site mode, the settings in the web
object will become defaults that apply to all sites. This allows you to group global settings into the top-level web
object and then override what you need for each site. Here is the full order of precedence for what settings will be applied:
settings in a .site.json
file inside a web root of a site
settings in an external site JSON file pointed to by the siteConfigFiles
setting in server.json
site-specific object in the sites
object of server.json
settings in the web
object of server.json
server.default
settings in CommandBox's global config settings
Since all sites for a given server do run inside the same JVM, there are some settings which cannot be customized on a per-site basis. They are as follows:
JRE/JDK the server runs on
JVM args, heap size
CF Engine/version
Console log
Tuckey Rewrites (part of servlet)
Environment Variables
Tray icon (there is a single tray icon for the entire server)
Everything normally set in the web
block of your server.json
can be configured separately for each site. These settings include:
GZIp enabled and GZip predicate
Access log
Use proxy forwarded IP
CommandBox Server Rules (Undertow Predicate Language)
SSL settings (HSTS, SSL Redirect)
Block CF Admin
Block flash remoting
Block sensitive paths
Security
Basic auth
Client cert auth
Security predicate
Custom error pages (404, 500, etc)
Mime types
Welcome files
Allowed file extensions
Directory browsing
Aliases/Virtual dirs
File cache settings
Case sensitive paths
Web root
Server Profile (even though this is not inside the web
object in your server.json
, it can still be set in a sites
block to override for that site.)
And remember, all of the settings in the section above can be defaulted for all sites in the web
block at the top of your server.json
and then overridden in the sites.siteName
block or in a .site.json
file.
There is much-improved console output now coming from Runwar when the server starts up. Add --verbose
or --debug
to your server start
command and you'll see site debug output at the top of the server start in the interactive job output:
Furthermore, once the actual server process gets underway, with the --trace
flag you'll see additional console output like so:
One of the most useful features of CommandBox is the ability to start an ad-hoc server quickly and easily. Any folder on your hard drive can become the web root of a server. To start up the server, cd
into a directory containing some CFML code, and run the start
command. An available port will be chosen by default and in a few seconds, a browser window will open showing the default document (index.cfm
).
To stop the embedded server, run the stop
command from the same directory.
You can start as many embedded server instances as you want. Each running server will add an icon in your system tray with the logo of your currently running engine. Click on it for options:
Stop Server
Open Browser
Open Admin
Open File System
When a server finishes starting, CommandBox will automatically open up the root of the site in your default browser. You can control the URL that is opened with
You can change the browser used to open all sites or override just the browser for a single site:
Or you can disable this feature entirely
If you don't want the tray integration, then you can turn it off in your server.json
with this setting.
Or turn it off at a global level in your config settings.
CommandBox's embedded server does not require any prior installations of any CFML engine to work. It does not use Apache, IIS, or Nginx. A very lightweight Java web server called Undertow is used and a context is programmatically deployed via a WAR file.
You should still have all the options you need to set up most local development servers quickly. The web-based administrator is available to you where you can edit any setting, add data sources, CF mappings, and mail servers. To see a list of all the parameters you can pass to the server start
command, refer to the CommandBox API Docs or run server start help
command directly from the CLI.
Any ComandBox environment variables present in the shell will automatically be passed to the environment of the server process. This means, given an example like this:
The CFML code running that server process will be able to "see" the foo
environment variable.
You can specify the CFML engine via the command line arguments:
This will start an Adobe ColdFusion 2018 server in your webroot. That's it!
By default, CommandBox uses the cfengine
slug to search for the engine on ForgeBox. The format is slug@version
where the version is optional. Ortus Solutions maintains the versions of the engines available on ForgeBox.
Supported engines are:
Adobe ColdFusion 9 **
Adobe ColdFusion 10
Adobe ColdFusion 11
Adobe ColdFusion 2016
Adobe ColdFusion 2018
Adobe ColdFusion 2021
Adobe ColdFusion 2023
Lucee 5
Lucee 6 (beta)
Railo 4.2
Lucee 4.5
Here are some examples:
Engines are downloaded and stored in your CommandBox artifacts folder. You can view your engines and clear them using the standard artifacts commands:
ColdFusion requires a username and password when CommandBox sets it up. When using the (default) development
CommandBox profile, the default username and password for the Adobe ColdFusion servers used are:
Username: admin
Password: commandbox
Since Lucee 5.3.4.46, Lucee no longer prompts you to set the admin password the first time running the admin. When using the (default) development
CommandBox profile, Lucee offers the option for you creating a password.txt file to set that initial password.
See also options to [control the admin password via CFConfig(https://cfconfig.ortusbooks.com/using-the-cli/commandbox-server-interceptors/server-start#set-individual-settings)].
Additionally, CommandBox can start any WAR given to it using the WARPath
argument.
If you run a regular start
command inside of a folder that has a /WEB-INF/web.xml
file, CommandBox will treat that folder as a WAR.
The cfengine
parameter can accept any valid CommandBox endpoint ID. That means it can be an HTTP URL, a Git repo, a local folder path to your company's network share, or a custom ForgeBox entry you've created. As long as that endpoint resolves to a package that contains these files, you're good:
box.json
Engine.[zip|war]
(file name doesn't matter)
CommandBox will download the package, unzip it and use the WAR/zip file as the engine for your app.
Normally, the artifacts cache isn't used for non-ForgeBox packages, but CommandBox will only download the engine once per server and then assume the file hasn't changed. You will need to forget the server to trigger a new download.
Here's an example of starting up a web server using a direct download link to a package containing a WAR file:
You can set the cfengine
and other related configuration options in your server.json
to use them every time you start your app.
These commands would create the following server.json
Just a reminder that starting a server with any command line arguments will save the arguments to your server.json
by default.
This command would add adobe@2023
to your server.json
. If this is not what you want, you can append saveSettings=false
or even --!saveSettings
when you start your server and CommandBox will not save the arguments you specify to your server.json
.
One minor difference to keep in mind is Lucee server and Adobe ColdFusion use a typical versioning scheme for java projects which looks like this:
However, and use the (semver) which is slightly different. Basically the build ID is moved to the end after a plus (+) sign.
The important thing to remember is, when starting a server via CommandBox always use the second format shown above since that is how ForgeBox recognizes each release.
As of version 5.3.0
, CommandBox will also recognize the fourth digit in 1.2.3.4
as a build ID if there is no plus sign in the version. This makes 5.3.4+80
and 5.3.4.80
equivalent.
Questions about what versions are available? No problem! Here are some ways you can find out:
View the last few versions via the CLI with the command
forgebox show lucee
Start typing your cfengine
and hit the <tab> key to invoke the tab-completion feature. This actually phones out to ForgeBox as you hit tab to get the current valid list of versions that match what you've typed so far
You can also follow the Lucee bleeding edge, which means every time you start your CommandBox server you'll get the very latest Lucee snapshot release. Please only use this for local development and not production!
It is a nice feature of CommandBox to have it automatically grab the latest version of your favorite CF engine every time it starts.
However, you may have good reason to NEVER want a new version automatically installed. In order to do this, you must specify a COMPLETE version number, including the build number, making sure to use the proper version format. This means you need a major, minor, patch, and build number.
We're now publishing CF Engines to ForgeBox based on the Lucee Light builds which allows you to start up a Lucee Light server. These are under a ForgeBox package named lucee-light
and we've also backfilled all the same versions that exist for the normal lucee
engine. Note, the three bullets points above apply to Lucee Light as well, Just replace lucee
with lucee-light
and you're good to go.
If you have questions about how to install extensions into a Lucee light server, please hit us up on Slack and we can show you several ways to manage that.
You may want to start up a local server that does not have a CF Engine such as Lucee or Adobe ColdFusion installed. You can do this as of CommandBox 5.1.0 by setting the cfengine
parameter to none
like so:
Or in your server.json
like this
This server will support everything that you are used to including the server.json
file, heap settings, ports, and virtual directories. The only difference is it will server everything as static files. (.cfm or .cfc files will not be processed)
A visual overview of CommandBox server deployments for both singular and Multi-Site configurations
This is what a typical ColdFusion deployment looks like. A separate web server sites in front, bound to ports 80 and 443 and proxies back to a Tomcat-based servlet:
For a CommandBox server, we replace the green box above with JBoss Undertow instead of Tomcat and we configure it on the fly with CommandBox. Here's a look under the covers at what the internal pieces of CommandBox look like for a single site server.
We have a set of HTTP/SSL/AJP listeners that feed through a single handler chain of configuration that funnel requests to the servlet deployment where the CF engine's libs are loaded. The default servlet serves static files via the singular resource manager configured to look in the web root.
Here is what a Multi-Site server looks like under the covers for Lucee Server (which works differently than Adobe). This is mostly the same regardless of whether you're using ModCFML or the new Multi-Site features.
Here the listeners funnel to a handful of different initial handler chains, which represent the different configuration between sites. The Lucee jars are loaded once and the Lucee Servlet Context exists once. Each site has a separate servlet deployment where a separate Lucee Web Context lives, along with their own CFML Servlet, default servlet, and resource manager configured for their separate web root.
In Multi-Site mode, static files are NOT served by the default servlet, but instead by an Undertow resource handler in the initial handler chain. The web.servletPassPredicate
controls what requests even reach the servlet. Static files are served without ever touching the servlet.
Here is what a Multi-Site server looks like under the covers for Adobe ColdFusion (which works differently than Lucee). This is the mostly the same regardless of whether you're using ModCFML or the new Multi-site features.
Like the Lucee example above, the listeners pass requests off to one of several initial handler chains, which represent different per-site configurations. However, we only have a single servlet deployment in this case and a single default servlet. The resource manager delegates out to sub-resource managers based on the site being accessed to switch out the web root as necessary.
In Multi-Site mode, static files are NOT served by the default servlet, but instead by an Undertow resource handler in the initial handler chain. The web.servletPassPredicate
controls what requests even reach the servlet. Static files are served without ever touching the servlet.
All the Multi-Site examples you need to get started with Multi-Site
This has several Multi-Site examples in the folders starting with the words multi-site-
. Here is an overview of a few of them.
Here is a basic server.json
configuring several sites. Here we have some defaults configured in the web
object for all sites, including a single HTTP binding to all IPs on port 80. There is a custom host alias configured on each site. There is a site called "default" which is set to the default site with default=true
in the site object.
This example server contains custom HTTP and SSL bindings for each server. You'll probably never need anything this complex, but we support it all! The HTTP port 81 binding on all IPs, SSL binding on port 444, and AJP binding on port 8010 are shared by all sites. Each site then adds additional bindings specific to the site. Needless to say, there are multiple URLs that lead to each site.
This example server configures some defaults in the web
object and then simply points to the web root of several sites where a .site.json
file is waiting to further configure each site:
And here are the .site.json
files from each of the web roots:
This example is similar to above, but instead of pointing to the web root of each site, it points to the site config file for each site, which is stored outside of the web roots:
In this example, the site1.json
, site2.json
, site3.json
, and default.json
files all live in the same directory as the server.json and would point to their respective webroots like so:
In this example, we have a single file globbing pattern that points to a directory of JSON files that define the sites:
In this example, we have a folder called sites-enabled
in the same directory as the server.json
with one or more JSON files. Here is an example:
Note the relative paths are always relative to this JSON file.
** Note: . To run ColdFusion 9 you must use an older version of CommandBox 3.x on Java 7 or run CommandBox 4.x on Java 8 update 92 or earlier. Several people are doing this, but beware your mileage may vary.
Visit the ForgeBox listing for the Lucee package and view all the versions in the versions tab
Lucee has a modular core and comes bundled with a bunch of extensions that approximate the functionality that comes bundled with Adobe ColdFusion. But that means you are loading the Hibernate libraries, PDF libraries or JDBC drivers even if you don't need them. There is a second type of Lucee server called "Lucee Light" which contains all the core engine, but with zero extensions. People creating custom docker builds for example will start with Lucee Light and then add back only the extensions their app needs. To get a feel for all the Lucee extensions available, see that lists all official extensions.
Full example here:
Full example here:
Full example here:
Full example here:
Full example here:
FusionReactor is a popular tool for monitoring performance and gathering metrics for ColdFusion and Java J2EE applications. You may wish to use FusionReactor with the servers you start up via CommandBox. We've created a CommandBox module that will add FusionReactor support to your CommandBox servers which you can view here on ForgeBox.
https://www.forgebox.io/view/commandbox-fusionreactor
The CommandBox FusionReactor module is a separate project that you can optionally install by typing this:
That's it-- now every server you start with the start
command will automatically have the JVM args added to it to load up FusionReactor.
There's nothing special you have to do in order for FusionReactor to load. A random port will be chosen for FusionReactor to use so you can have more than one server running at a time and each of them will have their own FusionReactor instance running. When you start a server, you should see some output similar to this:
To open FusionReactor in your browser, you can run the following command:
If you right click on the tray icon for this server, you'll see there is a new menu item at the bottom called Open Fusion Reactor
that will do the same thing.
FusionReactor is a commercial product and requires a license to use. If your company has a license for you to use on your PC, then you can register your CommandBox FusionReactor license with this command:
If you don't have a license, you can sign up for a trial and purchase a license from the http://www.fusion-reactor.com/ website.
By default, the license key will always be displayed on the home page after login. You can turn off the display of the key on a per-server basis or at a global level for all servers.
By default, the module always picks a random port to start FusionReactor on. You can also set your FusionReactor port on a per-server basis, or at a global level for all servers (if using the fancy host updater module which prevents port conflicts by binding each site to its own IP). The default behavior will still be to pick a random port if you don't specify one.
By default, the module will bind FR's port to the same host as your CommandBox web server. You can ask FR to bind to a separate host/IP on a per server basis, or a global basis.
You may want to turn the FusionReactor functionality on or off based on your testing or for specific sites. There is now an enable flag for just that. It can be set per server and for all servers as well.
You can set a license key per server if you wish like so:
The module is regularly updated to use the latest version of FusionReactor. Note however that your license key may not be for the latest FR version. When the internal default version of FR is updated for a major release, the version of the actual FR module will also have a "major" version increment. This is so you can always run upgrade --system
and you won't have to worry about suddenly getting a major FR upgrade one day that doesn't work with your license key.
If you want to upgrade your CommandBox FusionReactor module to a new major release, just re-run the installation command.
If you have an older FR license you want to use, you can specify the version of FR you'd like like so:
The installID
setting can be any valid CommandBox endpoint installation ID, which means you can point to a custom HTTP URL, or ForgeBox slug, etc.
As of version 4.0 of this module, the debugger libs will be added automatically for you based on your OS. To disable the debugger libs use the following setting:
There are a handful of JVM args we can use to set things like license key or password, but there are many many settings inside of FusionReactor that have no corresponding method to externalize them. These are stored in a file called conf/reactor.conf
inside of the FusionReactor home directory. If you want to script out settings such as
E-mail servers
Notification settings
Profiler settings
Request history settings
Then you can make a copy of a reactor.conf
file that contains the settings you want the point this module at the file to be copied over when starting the server so FR will pick it up and use it. Just need in mind that this setting will override any manual setting changes you make in the FR web admin every time you start the server.
reactor.conf
file somewhere for later usePoint your server.json
to the new file. Remember, non-absolute paths are relative to the directory the server.json
lives in.
Now, a fresh new server will have these settings.
Note: the reactor.conf
file may contain passwords or other sensitive information. It is in a java properties file format, so feel free to edit it and remove items you don't want. Also, take care when committing it to a source repo or making it web accessible so you don't reveal information. There is currently no support for environment variable expansions in this file, but perhaps we'll add it if it's useful.
The CommandBox FusionReactor module has passthrough settings for every documented JVM arg. Here are the remaining ones we haven't covered. If you want to know what some of these do, read the official FR docs on them.
Here's the module setting, followed by the JVM arg it creates. Remember, you can use environment variables in your server.json
to control these dynamically on a per-server basis!
fusionreactor.password - fradminpassword
fusionreactor.cloudGroup - fr.cloud.group
fusionreactor.requestObfuscateParameters - fr.request.obfuscate.parameters
fusionreactor.autoApplicationNaming - fr.application.auto_naming
fusionreactor.defaultApplicationName - fr.application.name
fusionreactor.EDSEnable - fr.ed.ds.enable
(version added: 8.1.0)
fusionreactor.EDSListen - fr.ed.ds.listen
(version added: 8.1.0)
fusionreactor.EDSPollTimeout - fr.ed.ds.polltimeout
(version added: 8.1.0)
fusionreactor.EDSMaxDataSize - fr.ed.ds.maxdatasize
(version added: 8.2.2)
fusionreactor.EDSTarget - fr.ed.ds.target
(version added: 8.1.0)
fusionreactor.EDSGroups - fr.ed.ds.groups
(version added: 8.1.0)
fusionreactor.ChatEnabled - fr.chat.enabled
(version added: 8.7.2)
fusionreactor.RESTRegisterURL - frregisterwith
fusionreactor.RESTShutdownAction - frshutdownaction
fusionreactor.RESTRegisterHostname - frregisterhostname
fusionreactor.RESTRegisterGroup - frregistergroup
fusionreactor.licenseDeactivateOnShutdown - frlicenseservice.deactivateOnShutdown
fusionreactor.licenseLeaseTimeout - frlicenseservice.leasetime.hint
By default, FusionReactor is only available on the FR port, and not the HTTP or HTTPS port. If you want to hit FusionReactor's web UI through your main web server on the standard HTTP port, then enable the external server setting. This completely bypasses the custom port and custom host discussed above.
This can provide a convenient method to make FR accessible, but remember to put appropriate lock-down rules on your external web server so FR is not publicly accessible. Also note if you have a web server such as Nginx only proxying traffic to .cfm URLs to CommandBox, you'll need to modify it to also proxy requests to /fusionreactor/
to CommandBox as well or this feature will not work and you'll just get an Nginx/etc 404 instead.
Sometimes you may wish to start a server on a computer that doesn't have access to the Internet. However, you may notice that running a command such as the following will throw an error trying to connect to ForgeBox:
That is because 5.x
is a semver range and not a specific version. CommandBox must connect to ForgeBox to see what versions of the CF engine lucee
can be found to use the latest one.
If you know that a CF engine is already downloaded in your server's artifacts directory, start your server with a specific major, minor, patch, and build version to skip the ForgeBox check.
NOTE: If this fails, check the location of the folder structure below the artifacts folder for it's exact path. e.g. /artifacts/lucee/5.0.0+252/lucee.zip - The box command for this would be: start cfengine=lucee@5.0.0+252 This follows the pattern: /artifacts/[server-type]/[server-version]/[server-type].zip Useful if you've manually downloaded the file from forgebox and need to rename it.
If CommandBox needs to connect to ForgeBox to resolve a version number and ForgeBox is unavailable, it will look in your local artifacts cache to try and find a cached version of that CF engine that satisfies your semver range. This means you may not get the latest version of that CF Engine, but at least your server will start up.
If a server isn't starting, the first thing to run is the server log
command. It will show you the console log for that server. Note, this dumps the entire log file to the console, which may be very large. We recommend using the tail
or --follow
tricks below.
If the log is very large, use the tail
command to just see the last few lines of it.
To get a live stream of the console log from a running server, use the --follow
flag and the command will continue streaming new lines to the console until you press Ctrl-C to stop.
You can also look at your server's access log (if enabled) and rewrite log (if enabled).
You can use the --console
flag to the server start
command to start a server in the foreground. The console log will be live-streamed to the CLI and the log will continue streaming as long as the server is running. Press Ctrl-C to stop the server and stop streaming the log file.
You can get additional information about a server start with the --debug
flag. When debug is set, the start
command will not exit immediately, but wait for the server to come up and live stream the debugging information and server logs to the console while the server is coming up.
You may still really be having issues getting your server to start up correctly due to a setting not getting picked up, rewrites not working, or maybe a jar not loading. You can "drink from the firehose" so to speak by turning on trace
level logging. This works best when starting the server via the console so you can watch the logging as it streams past.
Your CF engine (Lucee, Adobe, etc) or Java app may have application logs of its own and their locations will vary based on what you have running. In any case, they will most likely be located under the server home directory.
You can find out where your server home is by running:
You can also get the full path to your servlet's "out" log with this command:
This log file is the equivalent of your catalina.out file on a typical Lucee/Tomcat install or the equivalent of your coldfusion-out.log file on a typical ColdFusion install.
The Servlet's "out" log can be tailed with this command:
Your console "out" log will auto-rotate every 10MB to keep it from getting too big. Don't use the --debug
or --trace
flag on a production server or you'll get a lot of logging information! Without those flags, the "out" log doesn't log anything for each request. With debug enabled, you'll get basic information for each request that comes in as well as whether a rewrite rule fired, and with trace, you'll get a ton of information about every request as well as every local path resolution by the path resource manager.
There are many log files for Lucee. For the guide below, I'm assuming you haven't set a custom serverConfigDir or webConfigDir for your servers. If you have, adjust the paths for the server and web context to be whatever it is you've configured. Here are the three locations you'll find log file and is pretty much the same for Lucee 4 and Lucee 5.
Lucee's server context log files - The server context is located under the server home which you can find with the command server info property=serverHomeDirectory. Open that directory and then navigate to WEB-INF/lucee-server/context/logs/.
Lucee's web context log files - The web context is also located under the server home. Open that directory and then navigate to WEB-INF/lucee-web/logs/.
So, to give real examples-- a Lucee server I just looked at on my machine has the three folders of log files I just covered above in these locations:
Since Adobe doesn't have the separation of server and web contexts, it only has two log locations which are as follows on all versions.
ColdFusion server log files - The remaining log files are located under the server home which you can find with the command server info property=serverHomeDirectory. Open that directory and then navigate to WEB-INF\cfusion\logs/.
So, to give real examples-- a ColdFusion server I just looked at on my machine has the two folders of log files I just covered above in these locations:
CommandBox servers use a powerful Java-based web server which we've tested to have throughput just as good as Apache or IIS. You can enable "access" logs which output one line for each HTTP request (even for static assets like JS or image files) in the same "common" format that Apache web server uses.
View the location of this log or tail the log contents like so:
Your access log will be auto-rotated every day.
CommandBox servers use the java-based Tuckey rewrite engine for easy URL rewriting. There's a lot of good debugging information available to help figure out why your rewrites aren't working. You can enable a separate rewrite log to view this information. Keep in mind this can generate a lot of logging output.
View the location of this log or tail the log contents like so:
Your rewrites log will be auto-rotated every 10MB. The amount of information that appears in the rewrites log will be affected by the --debug
and --trace
flags when you start the server.
There is a feature you can use to dump all the header details for an HTTP request and response in the form of an Undertow handler called dump-request()
. Just include the following server rule in your server.json
To fire only for certain requests, you can pair the handler with any predicate you wish:
Then start your server with the --console
flag or tail the console with server log --follow
and you'll see info like this for each request:
It's important to note that each server you start opens a new Java process on your host operating system. This allows each server to have it's own settings and configuration independent of any other server. Start as many as you need and simply stop them when you're done. Just keep in mind each server gets its own heap space so keep an eye on your available RAM.
The embedded server instances are also a separate process from the actual CommandBox CLI process, which also runs on Java. This means you can open the interactive shell, start a few servers, then quit the shell, yet the servers will still continue to run. You can use the CLI to issue a stop
command in the servers web root, or just right click on the tray icon.
There is currently no way to have servers start automatically when your computer boots, though there's nothing preventing you from setting up a local script to run the start commands for you.
You may be used to having your server's WEB-INF folder living in your web root. The CommandBox embedded server still has a dedicated WEB-INF folder for each server you start, but it lives under the main CommandBox installation directory in your user folder. Changes you make to the WEB-INF such as adding jars or new tas will be persisted until you issue a server forget
command.
CommandBox stores information about each of the servers you've ever started inside ~/.CommandBox/servers.json
so it can remember settings from one run to the next.
You can see an overview of your servers and what state they're in with the server list
command.
If you have many servers, you can provide parameters to help filter the results from server list
To list only the servers that have been started in a given directory, use the --local
flag.
You can take a quick look at the what's been happening with the server log
command or use the server status
command to see more detailed information including the arguments used previously to start/stop the server.
Servers are uniquely identified by their full path, but they also have a short name which defaults to the immediate folder containing their web root. The stop
, start
, etc commands can be run in the web root for a server, or in any working directory as long as you reference the server's short name.
Another handy shortcut is the server cd
command that will change the current working directory of the interactive shell to the web root of a named server.
Info Server name is the first parameter to all server commands and tab completion works too, making it as easy as possible for you.
You can get information about a server using the server info
command. Add the --JSON
flag to get the data back in a JSON format. The property
parameter will allow you to retrieve a single value for scripting mashups.
If you want to wipe all configuration, logs, and WEB-INF files for a server, use the server forget
command. This will also remove any administrator settings you may have saved including data sources, mail servers, and server mappings.
You can forget all your servers at once too if you want to start with a clean slate. This command will stop and forget all servers.
You can easily forget all servers which have not been started for a certain period of time with the server prune
command. It accepts the number of days that need to have passed since a server was last started in order to prune it.
You can also get back just a JSON representation of servers matching the filter with the --json
flag. The JSON will be in the same format as the server list --json
command.
CommandBox allows you full control over the servers you start. This includes the port and host, custom JVM args, URL rewriting, web aliases, custom error pages, and custom welcome files.
Configuration can be set at several different levels:
Passed as parameters to the server start
command
Stored in a server.json
file for that server
Global defaults in the server.defaults
config setting
Internal defaults from the ServerService
Settings will be used in that order. Also, any parameters passed to the start
command will automatically be saved to your server.json
file unless you pass the --noSaveSettings
flag.
A lot of settings used to start a server involve file paths. Paths starting with a drive letter like C:/
, a UNC network path like \\
, or a leading slash like /
are considered absolute paths and will not be expanded. Try to avoid absolute paths if you want to make your server config portable.
Paths that start with a file/folder name like foo/bar.jar
or ../../lib/my.jar
are relative and the root folder that they are relative to depends on where there are specified.
If the path is passed as a parameter to the start command, the path is relative to the current working directory
If the path is in the server.json
file, it is relative to the folder containing the JSON file. (Remember the server.json
doesn't have to be in the web root!)
If the path is in a global server.defaults
config setting, it is relative to the web root of the server.
CommandBox has profiles you can assign to a server when you start it to configure the default settings. This is to provide easy secure-by-default setups for your production servers, and to make it easier to switch between a development mode and production mode.
There are 3 currently supported profiles. Custom profiles will be added as a future feature.
Production - Locked down for production hosting
Development - Lax security for local development
None - For backwards compat and custom setups. Doesn't apply any web server rules
You can set the profile for your server in your server.json
Which create this property
Or you can specify it when starting the server like so:
For , server profile can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
If a profile is not set, these rules are used to choose the default value:
If there is an env var called environment
, it is used to set the default profile (same convention as ColdBox MVC)
If the site is bound on localhost
, default the profile to "development". Localhost is defined as any IP address starting with 127.
If neither of the above are true, the default profile is "production". This makes CommandBox servers secure by default.
When profile is set to "production", the following defaults are provided:
web.directoryBrowsing
= false
web.blockCFAdmin
= external
web.blockSensitivePaths
= true
web.blockFlashRemoting
= true
When profile is set to "development", the following defaults are provided:
web.directoryBrowsing
= true
web.blockCFAdmin
= false
web.blockSensitivePaths
= true
web.blockFlashRemoting
= true
When profile is set to "none", the following defaults are provided:
web.directoryBrowsing
= false
web.blockCFAdmin
= false
web.blockSensitivePaths
= false
web.blockFlashRemoting
= false
The defaults above only apply if you do not have am explicit server.json
or server.defaults
config setting. If you have an explicit setting, it will override the profile's default. Therefore, if you set the profile
toproduction
but set web.blockCFAdmin
to false
, your CF administrator will be public, but the remaining production defaults will still be applied. This allows even the default profiles to be customizable.
It is common to protect pages on your site through your CF code that runs on every request. This does not protect static files like images, plus it can still expose extra surface area of your site for attack. CommandBox has a security system to block certain paths on your site at the web server level, so these requests never reach CF.
There are currently two authentication mechanisms you can enable in CommandBox. Any combination of them can be used to secure the protected portions of your site. When CommandBox determines that the current page requires authentication, it will check each enabled auth mechanism until it finds one that can validate the user.
Basic Authentication is built on a simple username/password list and challenges the user to provide credentials in their browser.
Client Cert auth is common for internal government sites and involves the user installing a private certificate on their PC which the server asks the browser to send while negotiation the SSL connection. Client certs are a PKI cert, and often times are stored on a CAC which is a physical card issued to the user.
There are more auth mechanisms we will add in the future including Digest Auth, Header Auth, and SSO. Contact us if you're wanting to sponsor any of these.
If you do not provide an auth predicate but you enable at least one auth mechanism, ALL PAGES on the entire site will be secured. This is quite secure, but often times you only want to protect a subfolder such as /CFIDE/administrator
or /lucee/admin
.
To limit the scope of what pages required authentication, you can specify an auth predicate, which follows the same syntax as .
We don't recommend using path()
or path-prefix()
as they are not case sensitive, which can lead to them being easily worked around if you are on Windows. Even regex()
is case-sensitive by default. Only use a case sensitive predicate matcher if your file system and web server are set to be case sensitive! If your server is case sensitive, then the example above can be simplified to this:
The most common auth predicates match a subfolder, but you are not limited to this. Anything valid in a server rule predicate can be used here, including HTTP method, headers, remote IP, etc.
Client Cert Authentication is common for internal government sites and involves the user installing a private certificate on their PC which the server asks the browser to send while negotiation the SSL connection. Client certs are a PKI cert, and often times are stored on a CAC which is a physical card issued to the user.
It is a requirement that the user hit your site via SSL in order for their browser to send their client cert OR for you to opt into accepting upstream client cert HTTP headers from a proxy or web server that is negotiating your SSL connection. It is recommended you configure your server to either disable HTTP or automatically redirect all HTTP traffic to HTTPS, which can be enabled with the web.SSL.forceSSLRedirect
setting.
Configuring your SSL connection to accept or require client certs is covered in the portion of the docs. It's important to note configuring your server to accept SSL client certs and using these certs to authenticate a user two different things. It's possible to accept (or even require) your client (browser) to send a client cert in your web.ssl.clientCert
settings but not use the authentication mechanism to protect parts of your site automatically. Any time a browser has sent a client cert, you will be able to access those details from the CGI
and request
scopes to do your own custom authentication. It is also possible to use Client Cert authentication but not have.
If you have configured your SSL Client Cert settings to accept, but not require client certs, this will allow a user to visit your site and not be challenged to provide a cert until they hit a page that your authPredicate
kicks in and requires authentication. Only then will the user's browser prompt them for a cert.
SSL Renegotiation, when enabled, will disable HTTP/2 AND TLSv1.3. Both of these are not compatible with SSL Renegotiation.
Even if CommandBox is not using SSL directly, but is sitting behind a proxy or web server that takes care of negotiating the client cert, you can still use client cert auth to protect pages on your site if you configure CommandBox to trust any SSL_CLIENT_CERT
HTTP request header.
Only enable this setting if you TRUST your upstream proxy and you know it will overwrite any potentially-malicious SSL_CLIENT_CERT
header from the client. SSL Certs received through this header will appear in the CGI
and request
scope and will be trusted the same as a client cert directly negotiated through CommandBox, but there will be NO trust chain verification. The header will be trusted blindly from your upstream server. This setting is off by default.
You can enable the client cert auth mechanism like so:
Once enabled, all pages on your site will be secured if you have no authPredicate
configured. Otherwise, only pages that match the predicate will be secured.
By default, when you enable client cert auth, CommandBox simply checks that some client cert is present. Remember, your SSL settings require you to provide a Trust Store or a list of trusted root CAs and only client certs which are trusted by one of those CAs will be negotiated. This may be enough security for you right there if you are only allowing certs signed/trusted by a specific root cert. The client cert trust store requires you to explicitly provide every single CA you want trusted. It does NOT use your Operating system's trust store, nor does it use Java's trust store, nor does it use Lucee Servers.
If a request is authorized via a client cert, the Subject distinguished name of the client cert will be present in cgi.remote_user
just like basic auth works.
You can filter down a subset of client certs you want to be accepted for client cert auth by specifying a full or partial subject DN. This will not limit the certs which are negotiated and appear in the CGI
scope. It will only limit the certs which are allowed to provide authentication for pages secured by the authPredicate
. A Subject Distinguished Name (SDN) contains one or more parts known as Relative Distinguished Names, or RDNs. They follow an LDAP name RFC and look like this:
You may provide a single Subject DN ...
or an array of Subject DNs to filter on...
The RDNs can be in any order and you can supply a PARTIAL Subject DN. CommandBox will match all RDNs regardless of order or case sensitivity. You are not required to provide the full Subject DN, but all RDNs you provide MUST be present in the incoming cert or it will be rejected.
You can also filter down a subset of client certs you want to be accepted for client cert auth by specifying a full or partial Issuer DN. This will not limit the certs which are negotiated and appear in the CGI
scope. It will only limit the certs which are allowed to provide authentication for pages secured by the authPredicate
. An Issuer Distinguished Name (IDN) look and work the same as Subject DNs.
You may provide a single Issuer DN ...
or an array of Issuer DNs to filter on...
The RDNs can be in any order and you can supply a PARTIAL Issuer DN. CommandBox will match all RDNs regardless of order or case sensitivity. You are not required to provide the full Issuer DN, but all RDSs you provide MUST be present in the incoming cert or it will be rejected.
If you require more specific parsing of the cert pieces, then you’ll need to disable the built in security in CommandBox and write your own code that runs on every request and parses the CGI variables manually to decide if you accept the cert.
server.json
ConfigurationCommandBox's web server supports enabling Basic Auth on your sites.
That will create the following data in your server.json
, which will be picked up the next time you start your server.
If there is no authPredicate
set, basic auth with secure ALL PAGES on the site. Once you set an authPredicate
, only the pages matching the predicate will require authentication.
The old setting location for Basic Auth (web.basicAuth
) will STILL WORK until the next major version of CommandBox, but should be considered deprecated. If both the settings exist (Ex: web.basicAuth.enable
and web.security.basicAuth.enable
), the new location will be given precedence.
Server scripts work just like , but they only apply to server-related interceptor points, and they go in your server.json
. If you have several servers in a folder with their own server-name.json
files, the server scripts can be different per server.
The interception points which will fire a server script are:
preServerStart
onServerStart
onServerInstall
onServerInitialInstall
onServerStop
preServerForget
postServerForget
Read more about when these interception points fire .
Configure server scripts like so in your server.json
:
Just like package scripts, you can also create ad-hoc scripts for a given server. They are executed with the server run-script
command. Define them as additional keys in the scripts
block.
And run them like so:
You can run several commands into a single one using &&
. You can also do this by specifying an array of strings instead of a string like so:
This can be much more readable for multiple commands. Note, this is functionality equivalent to using &&
, which means any erroring command will stop execution.
For , any auth settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
For , any client cert auth settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file. Just note, client cert auth settings will be shared by all sites using the same SSL binding.
Here is a look at what your full config could look like in your server.json
. Note this doesn't show the web.ssl.clientCert
settings which are .
For , any basic auth settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
CommandBox servers have a method of locking down secure URLs and or implementing any of the Undertow predicate and handlers via a nice text based language. Undertow supports a “predicate language” that allows a string to be parsed into a graph of predicates (conditions) and handlers (actions to take). Ex:
These rules can be used for any of the following:
Security - Block paths, IPs, or users
URL rewrites - Rewrite incoming URLs to something different
Modifying HTTP requests on the fly - Set headers, cookies, or response codes
Much of this functionality overlaps with the existing Tuckey-based rewrites in CommandBox, but this functionality is built directly into Undertow, has a more streamlined syntax, and allows for easier ad-hoc rules to be layered into a server that allows for you to have custom rules layered on top of built in rules. It can be used to replace what Tuckey does, or added on top.
If you have Tuckey rewrites enabled AND use the Undertow predicate-based server rules, the server rules will fire BEFORE the Tuckey rewrites.
Unlike custom Tuckey-based rewrites that must be placed in a single XML file, server rules can be provided ad-hoc in a variety of locations. They are combined and passed to the server in the order defined. This allows you to easily "layer" custom rules along with out-of-the-box lockdown profiles.
For maximum configuration options, the following mechanisms are supported for specifying the rules for a given server. Rules are processed in the order listed. i.e., a rule defined in your server.json
is processed prior to a rule in your server.default
config setting.
Ad-hoc rule array in sites
object or .site.json
for Multi-site server
Ad-hoc rule array in server.json
External rules files in the sites
object of the server.json
or .site.json
for Multi-site server
External rules files in server.json
in the order defined
Ad-hoc rule array in config setting server.defaults
External rules files in config setting server.defaults
in the order defined
CommandBox built-in rules (web.blockCFAdmin
, web.blockSensitivePaths
)
Any module listening to server interceptions can inject their rules wherever they please in the array.
server.json
RulesYou can specify ad-hoc rules in the web.rules
property as an array of strings in your server.json
as well as specify one or more external rule files in the web.rulesFile
property as an array or list of file glob patterns.
External rule files with a .json
suffix will be expected to be a valid JSON file containing an array of strings. Ex:
External rule files with any extension OTHER than .json
will be expected to be a raw text file with one rule per line. Emtpy lines are ignored and the rules are processed in the order defined.
Rules specified directly in the server.json
or in an external JSON file must be escaped for the JSON they are a part of. Using a plain text external file can help readability since no additional escaping is required for the rules.
server.defaults
RulesLike all other config server defaults, they follow the same pattern as the server.json
file.
For Multi-Site, server rule settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
You can comment out any rule (whether it's in JSON or a text file) by proceeding it with a pound sign (#
).
The Undertow-based web server built into CommandBox will only serve up static files if they are in a list of valid extensions. This is to prevent prying eyes from hitting files they shouldn't be able to access on your server.
The current list of valid extensions is:
If you have a common static file you need to serve, you can add your own custom extensions to the list like so:
For Multi-Site, allowed static files settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
If you've used mod_rewrite
with Apache web server, you may be familiar with its Rewrite Map functionality, which allows you to create dynamic rewrites based on a text file of mappings. We have a similar feature built on Undertow's Server Rules that mimics Apache's feature.
Note, when in Mult-Site mode, each site has its own rewrite maps, even if they share the same name. There is no overlap between sites!
There is a rewrite-map()
handler which declares a named map file. It accepts an absolute path to the rewrite file, and case sensitivity flag.
The file format matches that of Apache's rewrite map functionality.
Lines starting with #
are a comment
empty lines are ignored
First space-delimited token becomes the key
All remaining tokens become the value
Lines with a single token default the value to an empty string
Here is an example file:
If the date modified on the rewrite map file changes on disk, the data will be automatically re-loaded into memory.
There are two handler/predicates you can use to interact with the rewrite map. Make sure these are in your list of Server Rules AFTER the map definition.
There is a rewrite-map-exists()
predicate which will tell you if a given key exists in the map (Apache doesn't have this)
You can pair this predicate to only use the rewrite map if there is a match.
There is a new %{map:name-name:mapKey|defaultValue}
exchange attribute which mostly follows Apache's syntax. The only limitation is nested exchange attributes must use [] instead of {} due to an Undertow parsing issue).
In the example above, we're using a regex predicate to extract the text after /foo/
in the URL and then we reference that capture group as $[1]
which we pass in as the key to the map. If there is no key in the map for that value, we default to 99
.
So, given our example rule map file above, the url
would be rewritten to
CommandBox's server rules are based directly on the "Predicate Language" feature of JBoss Undertow. All of the official documentation for Undertow's predicate language applies to CommandBox. CommandBox doesn't limit the power of what Undertow provides at all. In fact, we give you some additional out-of-the box predicates and handlers you can use.
There are three concepts you need to understand and you'll be writing your own rules in no time.
Handler - A wrapper around the request that takes some sort of action such as returning a status code or rewriting the request.
Predicate - A conditional that evaluates to true or false. Used to Conditionally apply a handler
Exchange Attribute - An abstracted way to refer to any piece of information about the request or response. Can include URL, query string, cookies, headers, or CGI variables.
Since the parsing of your rules is handled by Undertow, it is case sensitive in many areas and CommandBox cannot control this. The following must always be lower case:
Predicate names
Handler names
Parameter names
Keywords like and
, or
, else
The full undertow docs can be found here: https://undertow.io/undertow-docs/undertow-docs-2.0.0/
A handler will take action on the request. This can redirect the request, rewrite it, abort it, or modify attributes of the request such as setting an HTTP header or status code. If the predicate is omitted, the handler will always fire for all requests. Ex:
set() - Sets an exchange attribute (see below)
rewrite() - Rewrite the request URL
redirect() - Redirect to another URL
header() - Sets an HTTP response header
set-error() - Set HTTP response code and returns the corresponding error page
ip-access-control() - Configure IP-based allow/deny rules (wildcards and IP ranges allowed)
done - Skips remaining rules
request-limit() - Limits concurrent requests
restart - Restarts process back at start of predicate rule chain (combine with rewrite, etc)
proxy() - Creates a proxy to a single host
load-balanced-proxy() - Creates a round robin reverse proxy to a list of hosts
allowed-methods() / disallowed-methods() - Enforces whitelist/blacklist of HTTP methods on current request
A handler is called using the “name” from the docs and passing any required parameters. Params can be named or positional (if there is only one). Quoting values is only required if they have a space, comma or brace. The following are all equivalent:
Handler parameters that accept an array use the Java array literal syntax which is a comma-delimited list of values in curly braces.
More than one handler can be run by wrapping them in curly braces and using semicolons between them
A chain of handlers can be configured for the true AND false evaluation of a single predicate using the “else” keyword.
A predicate is a condition that must be matched for the handler to kick in. If using path-based predicates on Windows, make sure to use the -nocase
version for security rules since your file system is not case sensitive.
path()/path-nocase() - match the incoming request path
path-suffix()/path-suffix-nocase() - match full file/folder names at the end of the path like file.cfm
path-prefix()/path-prefix-nocase() - match full file/folder names at the start of the path like /lucee/admin
is-file / is-directory - check if the %{RELATIVE_PATH}
is an existing file or directory on disk. While relative path is the default, you can pass another exchange attribute to check as is-file( %{q,myQueryParam} )
method() - Match the HTTP method
regex()/regex-nocase() - Match a regular expression against any exchange attribute
equals()/equals-nocase() and contains()/contains-nocase() - Do a text compare on any exchange attribute
path-template() - match a path with placeholders like /foo/{bar}
and the placeholders become variables for use in later predicates or handlers in the chain.
A predicate is called by placing parentheses after the name and passing in the required arguments as specified in the docs for that predicate. Quoting values is only required if they have a space, comma or brace. The following are all equivalent:
Complex conditions can be constructed with more than one predicate using the keywords “and” or “or”.
A predicate can be negated with the keyword “not”
Exchange attributes are an abstraction Undertow provides to reference any part of the HTTP request or response. There is a textual placeholder that can be used in predicates and handlers that will be expanded in-place.
%{REMOTE_IP} - Remote IP address
%{PROTOCOL} - Request protocol
%{METHOD} - Request method
%{REMOTE_USER} - Remote user that was authenticated
%{RESPONSE_TIME} - Time taken to process the request, in ms
%{c,cookie_name} - Any cookie value
%{q,query_param_name} - Any query parameter
%{i,request_header_name} - Any request header
%{o,response_header_name} - Any response header
%{REQUEST_URL} - The requested URL
%{RELATIVE_PATH} - The portion after the domain
${anything-here} - Any value from the predicate context (such as regex capture groups or path-template placeholders)
Use an exchange attribute like you would a variable as the parameter to a handler or predicate.
Attributes, Cookie, query params, request headers, and response header names are not case sensitive.
These are all equivalent:
By default, CommandBox will open your browser with the host and port of the server. You can customize the exact URL that opens. This setting will be appended to the current host and port.
Or you can completely override the URL if your setting starts with http://
.
For Multi-Site, the openBrowserURL can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file. The browser will not open automatically, but this setting will control the options in the tray menu and the server open
command.
The syntax on this page is deprecated. It will still work for the foreseeable future, but we recommend using the new bindings
object instead which is much more powerful and allows multiple bindings.
The start
command will scan your system and find a random port that is not currently in use to start the server on. This ensures that multiple embedded servers can run at the same time on the same host without collisions. Ensure any redirects in your applications take the port into account.
For Multi-Site, any port and host settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
You may want to set a specific port to use-- even port 80 if nothing else is using it. Pass the HTTP port parameter to the start command like so:
It is also possible to save the default port in your server.json
. Add a web.http.port
property, or issue the following command:
Now every time you start
your server, the same port will be used.
If the server won't start or is unreachable, make sure it's port is free with your operating system's netstat
command. On Unix-based OS's:
You can start your server to listen for SSL connections too.
You can customize what SSL protocols your HTTPS listener will respond to with the following XNIO option. Supply a comma-delimited list of valid protocols.
HTTP/2 is a newer standard of HTTP supported by all modern browsers. HTTP/2 is enabled by default any time you are using an HTTP/HTTPS listener, however all major browsers will only allow the server to negotiate HTTP/2 over an HTTPS connection. HTTP/2 runs over the same port and only changes the exchange between the server and browser. You can disable HTTP/2 support like so:
If you want to confirm whether your browser is using HTTP/2, you can open your debugging tools and look at the network requests. You may need to add the "protocol" column in the UI. HTTP/2 will usually show up as something like "h2" in the protocol column.
You can start your server to listen for AJP connections too.
CommandBox's AJP listener (provided by Undertow) is already protected against the Ghostcat vulnerability. However, if you would like to set utp an AJP secret as well to ensure all requests coming into the AJP listener are from a trusted source, you can do by setting the web.ajp.secret
property.
For this to work, you must also configure your AJP proxy in your web server to send the same secret! For requests received to the AJP listener which do not contain the secret, a 403
status code will be returned. You can customize the output of the 403 page via the Error Pages settings.
The AJP secret is implemented via a Server Rule. Feel free to add your own server rule instead of this setting if you want to customize how it works.
Your application may rely on a specific host name other than the default of 127.0.0.1
. You can set the host to anything you like, but you must add a host
file entry that resolves your host name to an IP address assigned to your network adapter (usually 127.0.0.1)
If you have multiple IP addresses assigned to your PC, you can bind the server to a specific IP using the host
parameter.
A server configuration can only have one host entry. If you require your server to be available on multiple IP addresses of the machine it runs on, you can set the host to 0.0.0.0. This will effectively bind the server to all network interfaces (including local).
Or save in server.json
Most modern browsers allow you to make up any subdomain you want before localhost such as mySite.localhost
and will simply resolve them to localhost
(127.0.0.1
) even without a hosts file entry. CommandBox now supports using these domains and will bind your server's ports to localhost even without using the commandbox-hostupdater
module.
There are endless combinations of predicates and handlers you can apply to your apps. Here's an assortment of examples to get you going. Many of these are contrived, but are just mean to show the range of syntax and functionality.
Rewrite a URL:
Stop processing rules for a given request:
For all GET requests, set a response header called type
with a value of get
If the incoming path ends with .css
it will rewrite the request to .xcss
and set a response header called rewritten
to true
.
Redirect all jpg requests to the same file name but with the png extension. The ${1}
exchange attribute is used to reference the first regex group.
Set a request header for all requests that you can access in your CFML app just like a normal HTTP header.
Set a Cache-Control response header only for default index pages(ie: index.html or index.cfm) in any folder.
Set a response header for a specific file.
Match certain SES-style URLs and store the place holders (referenced as exchange attributes) into HTTP request headers.
In this example, hitting the server with /restart
skips the first rule, the second rule rewrites the request and then restarts back at the first rule which fires the second time through.
Block access to a URL unless coming from a specific IP.
For more control over IP address matches, use the ip-access-control()
handler.
Leading slash is NOT required. Both of these rules are the same:
It is not required to include .*
_ at the end of a regex path unless you’ve set full-match=true
_
Perform a regex a case insensitive search like so:
When attribute values are not quoted, all leading and trailing whitespace will be trimmed. The following are all the same:
But this example is different. The leading and trailing spaces will be preserved in the path string.
Basic MVC rewrite:
Add a CORs header to every request
Rewrite requests to a sub folder based on the domain
Custom SES URL rewrite that turns 6 digit product code into a query string. (If this rule goes in your server.json
, you'll need \\
in front of the dollar sign to escape it twice. Once for the system setting expansion and once for the JSON file.)
Reject requests using an unknown host header.
Create reverse proxy to multiple hosts
Create reverse proxy to a single host
CommandBox bundles some custom predicates and handlers to make your life easier.
The predicate cf-admin()
will returns true
if the incoming URL is to the Lucee or ColdFusion admin:
The handler block-external()
blocks any request not from localhost with a 404 response code. You can pair this with any predicate you choose.
The handler block-cf-admin()
blocks any request to the Lucee or ColdFusion admin with a 404 response code.
You can build your own predicates and handlers by compiling java classes that implement the io.undertow.predicate.PredicateBuilder
or io.undertow.server.handlers.builder.HandlerBuilder
interfaces. If the proper service metadata is present in your jar's META-INF folder, undertow will automatically find and register your builders via Java's service loader.
This isn't super difficult but involves a few moving parts. If you're interested in writing your own handlers and predicates to use in your server rules, reach out on the mailing list and we'll walk you through it.
You can see the custom handlers and predicates documented above in our Runwar source code here:
Custom handlers:
Custom Predicates:
CommandBox has a few baked in rules that you can apply ad-hoc or as part of a server profile
.
web.blockCFAdmin - Returns 404 error page for any Adobe CF or Lucee Server admin administrator paths
web.blockSensitivePaths - Returns 404 error page for common config files such as box.json
or .env
web.blockFlashRemoting - Blocks all paths related to Flash and Flex remoting calls
If you want to customize the rules above, simply turn them off and include the rules directly in your server.json
where you can modify them as you see fit.
This setting has three possible settings:
true - Block ALL access to ColdFusion and Lucee admins
false - Do not block anything
external - Only block access not coming from localhost.
The exact rule activated when you set this property to true
is:
The exact rule activated when you set this property to external
is:
This setting only allows true
/false
. This is a bit of a catch-all rule for any sort of paths that a user should never be able to make on production that could reveal information or access secret parts of your CF installation. When set to true
, the following rules are activated:
When the profile
is set to production
, the following rule is also added which blocks the ColdFusion RDS access from CF Builder and access to TestBox runners:
If you need to legitimately access any of these paths, you'll need to turn off this setting and custom-add the rules that you want to keep. This setting is a convenience that adds several rules at once.
This setting only allows true
/false
. When set to true
, the following rules are activated:
If you need to legitimately access any of these paths, you'll need to turn off this setting and custom-add the rules that you want to keep. This setting is a convenience that adds several rules at once.
What if you want to go one step deeper? For instance, the blockSensitivePaths
setting blocks a whole bunch of stuff all in one shot. An example might be wanting to open up JUST the RDS IDE integration for your developers, which funnels through the /CFIDE/main/ide.cfm
path which you can see is blocked above.
The solution to this is quite simple and is all based on the ORDER in which your rules are processed. Built-in CommandBox rules are the last to process. This means that if you hijack the predicates with a custom rule FIRST, you can override the behavior of the built in rules. So, if we want to allow access to the /CFIDE/main/ide.cfm path, we just need to add a custom rule that matches that path and then aborts the predicate chain so no further rules fire.
Which gives you the following server.json
The done
handler is what bypasses all subsequent rules for the request.
Since your custom rules are processed BEFORE the built-in rules, that also means that you have the ability to accidentally bypass security rules by applying another rule that intercepts the request! By default a custom rule won't block subsequent rules from firing unless you rewrite the request or use the special done
handler.
You can configure the IP, Port, and hostnames for your servers in the bindings
object, which is new in CommandBox 6.0. Whereas the defaults to binding to localhost
, bindings will default to all IPs or 0.0.0.0
which is more consistent without mainstream web servers work.
The bindings
object goes inside your web
object in server.json
and for servers, you can also specify bindings
in each site as well.
There are 3 types of bindings, some of which have additional information that is specific to them
HTTP
SSL
HTTP/2 support
Server certs
Client certs
AJP
AJP secret
Each type of binding is represented by an object of that name inside the bindings
object. Everything is optional, so only specify what you need
Every binding has
IP address (can be *
or 0.0.0.0
which means All IPs)
Port
zero or more hostnames (An empty string or *
will match all hostnames)
Note, hostnames are only really used for Multi-Site servers. If you only have a single site defined, all traffic will be served by that site regardless of the hostname of the incoming request.
The default key to use is called listen
. You can specify JUST a port, which will default to all IPs and all hostnames:
We can also specify the IP address as an IP or a *
or 0.0.0.0
before the port delimited by a colon:
As an alternative to the listen
key, you can specify IP
and port
keys. This can be handy if you plan to override just part of a binding via env vars.
This syntax is mutually exclusive with the listen
key.
Add in as many hostnames as you need as a comma-delimited list or an array
More than one HTTP binding would look like this, where the same object is used, but inside of an array.
AJP
bindings work the same as the HTTP
binding examples above, but can have the addition of a secret
key. All AJP connections to this port will need to come bearing the required secret.
Technically, HTTP/2 can be enabled on either HTTP
or SSL
bindings, but most browsers will only negotiate HTTP/2 over SSL
.
HTTP/2 is enabled by default. The legacy web.http2enable
flag is still obeyed and will be applied to any bindings in that block unless otherwise overridden.
To configure a single SSL Server cert, you can specify the following keys inside the binding:
certFile
- A PEM-encoded DER cert or a PFX file
keyFile
- THe Private key (not used for PFX)
keyPass
- The key pass or PFX pass. Blank if not used
To configure multiple SSL certs on the same binding, use a certs
array of objects containing the same keys above for each cert you want to specify.
CommandBox will automatically use SNI (Server name Indication) to choose the correct cert to use when negotiating the SSL handshake based on the hostnames in each cert's
Subject Common Name (CN)
SAN (subject alternative names)
CommandBox will also handle SNI for wildcard certs as well.
If using Client Cert authentication, you can also specify client certs for each SSL binding in an object called clientCert
. This object can have the following child keys:
mode
CACertFiles
CATrustStoreFile
CATrustStorePass
SSLRenegotiationEnable
And to test/debug your rules, start your server with the trace flag and tail the console output. Every hit in your browser will output several lines of debugging for each rule that is processed.
With the custom rule above, you'd see something like this:
If CommandBox is running a server behind a trusted proxy which is known to set the X-Forwarded-For
HTTP header, then you can enable this setting for the remote IP in your CF engine's cgi
scope to represent the upstream IP.
This is disabled by default. Otherwise a malicious client could send a fake X-Forwarded-For
HTTP header to make it look like their traffic was coming from a trusted IP such as 127.0.0.1
to bypass any IP-based restrictions. Only enable this if you trust the proxy CommandBox is sitting behind. This should never be enabled if CommandBox is directly accessible on the internet.
Enable for all servers like so:
For , Proxy IP settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
When using a CommandBox web server in production, you may wish to force your users to visit your site over HTTPS for security (and for HTTP/2 to work). However, it is desirable to still have your web server listening on HTTP so a user just typing your address in his browser can still connect to HTTP and then redirect.
CommandBox can be configured to redirect all HTTP traffic over to HTTPS with the following rule. The redirect will use a 301
status code and will include the URL and query string. The redirect will only fire for GET
HTTP requests since redirecting a form POST
would lose the form fields (request body).
Or in the server.json
as:
For , HTTPS redirection settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
If you want to customize how this redirect happens, you can skip this setting and manually add the following , which is basically what the setting above does automatically:
If you want to go one step further, you can add a Strict-Transport-Security
header to your site. This instructs the browser to automatically use HTTPS every time the user visits your site again. With an HSTS header, once your browser has cached the fact that you want HTTPS to always be used, even if the user just types your domain and hits enter, the browser will change it over to HTTPS before sending the request. This prevents having an initial HTTP request before the redirect kicks in.
HSTS headers can have a "max age" set, which tells the browser how long to "remember" to use HTTPS. This defaults to 1 year if you do not override the value. The max age is set in second. So 31,536,000 is one year. You can also set whether you want the HSTS header to apply to all sub domains of your site. The default is false
for this setting.
Here is how you enable HSTS. Only the first web.SSL.HSTS.enable
setting is required. The rest are optional.
Or in the server.json
as:
Accepting a client cert as part of the SSL negotiation is a totally separate idea as using the existence of a client cert to authorize a given request. This is why the settings are in two different place in the server.json
. You can have CommandBox ask (or require!) the browser to hand over a client cert, but all that does is set a bunch of CGI variables and servlet request attributes to document what the incoming cert is. The same client cert details can also be passed from an upstream proxy which negotiated the SSL connection and the details can be sent via HTTP headers to CommandBox to use for request authorization. Therefore, CommandBox can enable client certs at the SSL level and NOT enable request authorization, or it can disable its own SSL client cert negotiation but still perform request-level authorization based purely on upstream headers. The two features are not mutually dependent. To read how to have CommandBox automatically protect portions of your site based on a client cert, .
To enable client certs to be negotiated by CommandBox SSL must be enabled, and then web.bindings.ssl.clientCert.mode
can be set to one of the following options:
NOT_REQUESTED - (default) SSL client authentication is not requested. (same as “ignore” in IIS)
REQUESTED - SSL client authentication is requested but not required. (same as “request” in IIS)
REQUIRED - SSL client authentication is required. (same as “require” in IIS)
CommandBox will NOT use your OS trust store nor your Java trust store, nor Lucee Server's trust store by default to establish a trust chain for incoming client certs. You must specify the trusted root CA certs that you want trusted. ONLY client certs trusted by one of these CAs will be accepted. Any intermediate certs must also be included. You can specify a comma-delimited list of absolute or relative paths OR an array of strings in the web.bindings.ssl.clientCert.CACertFiles
setting that point to any number of public keys in a DER format (typically .crt or .cer extension)
or
If you have a large number of trusted CA’s, you can specify a JKS trust store (same format as Java’s cacerts
file) along with the password for the store in the web.bindings.ssl.clientCert.CATrustStoreFile
and web.bindings.ssl.clientCert.CATrustStorePass
file. All CAs in that trust store will be used to validate incoming client certs.
The user's browser will ONLY be able to send client certs signed/trusted by one of the CAs you specify. All other certs will be rejected. If your mode is set to REQUIRED, that means your user would never be able to reach any CF pages at all (unless you are using SSL renegotiation which is .
server.json
ConfigurationHere's an example of what your config could look like:
If both a trust store AND individual trusted CA's are provided, CommandBox will use all of them.
When a valid client cert is present, the following CGI
variables will be available to your CF code. If client certs are “requested”, these CGI variables will be wiped from any upstream sources so you can always trust them to be set from CommandBox, even if they are empty. There are several duplicate values since we are mimicking IIS, Apache, and Nginx client cert implementations for maximum compatibility.
CGI.SSL_CLIENT_CERT
- PEM-encoded cert (base 64 string)
CGI.X_ARR_CLIENTCERT
- PEM-encoded cert (base 64 string)
CGI.SSL_CLIENT_S_DN
- The Subject distinguished name of the client cert (CN=foo, O=bar, OU=baz)
CGI.CERT_SUBJECT
- The Subject distinguished name of the client cert (CN=foo, O=bar, OU=baz)
CGI.CERT_KEYSIZE
- The key size of the negotiated SSL connection
CGI.CERT_SERIALNUMBER
- The serial number of the cert in the format 91-7e-5f-a5-b2-20-a1-8b-4c-d0-40-3b-1c-a1-a8-58
CGI.SSL_CLIENT_M_SERIAL
- The serial number of the cert in the format 91-7e-5f-a5-b2-20-a1-8b-4c-d0-40-3b-1c-a1-a8-58
CGI.SSL_CLIENT_I_DN
- The Issuer distinguished name of the client cert (CN=foo, O=bar, OU=baz)
CGI.CERT_ISSUER
- The Issuer distinguished name of the client cert (CN=foo, O=bar, OU=baz)
CGI.SSL_CLIENT_VERIFY
- Matches Apache HTTP. Values will be "SUCCESS" or "NONE"
CGI.SSL_SESSION_ID
- Unique ID of the SSL connection
Note, some of these vars may not appear when you cfdump out the CGI
scope, but will still be available when you specify cgi.var_name
Due to some differences between Adobe ColdFusion and Lucee Server, the above variables are loaded as HTTP Request Headers in Lucee and Servlet Request Attributes in Adobe ColdFusion. You can access them in either engine though through the CGI
scope, but they may be case sensitive (always upper case)
The following servlet request attribute will also be set, which are accessible in a case sensitive manner from both Adobe and Lucee Server request
scopes:
javax.servlet.request.cipher_suite
- The cipher suite of the SSL connection such as TLS_AES_128_GCM_SHA256
javax.servlet.request.key_size
- The key size of the negotiated SSL connection
javax.servlet.request.ssl_session_id
- Unique ID of the SSL connection
javax.servlet.request.X509Certificate
- An array of java.security.cert.X509Certificate
instances representing the certificate chain. These cert objects contain the same data as the PEM-encoded headers.
javax.servlet.request.X509Certificate.issuerDNMap
- A struct containing all the parts of the Issuer distinguished name. So for (CN=foo, O=bar
) there would be a key for CN
and O
in the struct with respective values of foo
, and bar
. USE THIS instead of regex on the full Issuer DN because this map is generated by following the exact RFC for LDAP names.
javax.servlet.request.X509Certificate.subjectDNMap
- A struct containing all the parts of the Subject distinguished name. So for (CN=foo, O=bar
) there would be a key for CN
and O
in the struct with respective values of foo
, and bar
. USE THIS instead of regex on the full Subject DN because this map is generated by following the exact RFC for LDAP names.
Access these request vars like so in CFML
Note using quoted string inside of bracket notation is required not only due to the periods in the variable name, but also to preserve the case-sensitivity of them.
All of the CGI and request vars above can also be present even if CommandBox’s built in client cert negotiation is not enabled if you have PEM-encode headers being sent from your upstream web server. However, you must explicitly tell CommandBox to trust these headers. Only do this if you trust the upstream proxy to always set trusted values into these headers. Enable this by setting the web.security.clientCert.trustUpstreamHeaders
key by setting it to true
. Them CommandBox will look for the SSL_CLIENT_CERT
, SSL_CIPHER
, and SSL_SESSION_ID
HTTP request headers and associate those certs with the request just as though CommandBox had negotiated them itself.
The syntax on this page is deprecated. It will still work for the foreseeable future, but we recommend using the instead which is much more powerful and allows multiple bindings.
The syntax on this page is deprecated. It will still work for the foreseeable future, but we recommend using the instead which is much more powerful and allows multiple bindings.
Turning on SSL in your web server will will enable SSL without an approved SSL certificate. If you need an official certificate so you don't have to confirm your SSL connection you can add these entries
The cert file and private key can be a PEM encoded file, or a DER-format binary file.
You can also use a PFX file (PKCS #8) by specifying it in the web.ssl.certFile
setting and then put the password for the PFX file in the web.ssl.keyPass
setting. You won't use the web.ssl.keyFile
setting for a PFX since the private key is contained in the main file.
For , SSL Server Cert settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
Although free certificates are available (e.g LetsEncrypt) this is not very convenient, because these certs are valid only for three months. Automatic renewal it is difficult if your dev site is not accessible from the web. For a few dollars a year (< 10) you can apply for a domain validated certificate from companies like Comodo, RapidSSL, Trustwave, Digicert, Geotrust and others or a reseller for these certs. For a domain validated certificate you need a valid domain which is under your control which means (depending on provider):
mail is sent to domain owner
or mail is sent to well-known administrative contact in the domain, e.g. (admin@, postmaster@, etc.)
or you can publish a DNS TXT record
So, now you have a valid domain, you have to generate a SSL key and a SSL Certificate Signing Request. With the CSR you can apply for the certificate. Generating a key and CSR with openSSL
This will generate output and some questions, and will finally result in a key file named dev_mydomain_com.key
and a certificate signing request (csr) named dev_mydomain_com.csr
You have to enter Country Name, State and City. Organization Name is preferably the same as the domain owner. Organizational Unit Name will not be checked, so enter something simple such as ICT Common Name is the host name for your site, such as dev.mydomain.com
You can skip Email Address and optional company name. For development you don't need a challenge password, which means your key file is NOT protected. But don't give this key to others or protect it with a challenge password. If you protect your key you have to server set web.SSL.keyPass=MyChallengePassword
Now you have a CSR, which you can submit at your SSL provider. They will send you a certificate file (*.csr), and probably one or more intermediate certificates. Create a new my.csr
file and copy everything from your certificate file into it, and append the intermediate certificate(s). Now you have a valid my.csr
certificate file and a key file. Place both files in a location accessible for your CommandBox and enter the corresponding paths to web.SSL.certFile
and web.SSL.keyFile
For more information on how to configure and use client certs, check out our .
For , HSTS settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
The HSTS header is added via a . Here is what the rule looks like in case you want to manually add the rule to customize it.
For , client cert settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file. Client cert settings will be shared for all sites bound to the same IP and Port.
If the user's browser sends a client cert which is trusted by one of your trusted CAs, then the details of the cert will be available for Client Cert Authentication as . There are also a number of CGI
and request
variables automatically made available to you any time a client cert was presented. These variables will be available on every page, not just the first page where they select their cert.
You can customize the error page that CommandBox servers return. You can have a setting for each status code including a default error page to be used if no other setting applies.
Create an errorPages
object inside the web
object in your server.json
where each key is the status code integer or the word default
and the value is a relative (to the web root) path to be loaded for that status code.
This is what you server.json
might look like:
You can set error pages via the server set
command like this:
For Multi-Site, custom error page settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
If your error page points to a CFM file, you can get access to the original path being accessed for 404s and the error that was thrown for 500s. To see all the request headers that are available, use the following snippet of code:
An example of getting the original missing path in a 404 in Lucee would look like this:
In Adobe ColdFusion, you can access ServletRequest
Attributes directly via the CGI scope:
CommandBox will automatically set the content type in the HTTP response for common static file types. If you come across a file extention that doesn't have the correct type, you can set it like so in your server.json
:
Which creates the following
In the above example, hitting a file such as foo.log
would come back with a text/plain
content type header.
This setting will override any <mime-mapping>
tag in your web.xml
file.
For Multi-Site, MIME Type settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
By Default, your servers start using the same version of Java that the CommandBox CLI is using. For people needing to run Adobe ColdFusion 9, or who just want to do some testing on different JREs, you can point each of your servers at a custom JRE and CommandBox will use it when starting the server.
if you already have a JRE downloaded somewhere on your hard drive, you can manually point the server at it, or you can simply tell CommandBox which version of java you'd like, at it will automatically download that version of OpenJDK for your server to use (if it's not already downloaded)
Point CommandBox to an existing java install like so:
To set the default version of Java for all the servers you start on your machine, use the global config setting defaults.
To let CommandBox take over and acquire Java for you, pass an installation endpoint ID to the start
command
or set it in your server.json
or set a default for all servers
To review what possible IDs you can use to dial in your exact Java version, read the docs on our Java endpoint. You don't need to manually install Java CommandBox will do that for you. You just need to provide a valid ID so CommandBox knows what you want.
In some cases you might not want to interact with the command line manually to setup an environment, in particular in production setups. If you prefer to setup your server via a server.json file, the same syntax for valid IDs applies to setting your JVM ID:
To make it easier for you to manage the Java installations CommandBox makes for you, we have a namespace of commands you can use. The Java versions CommandBox installs automatically for your servers to use are stored in a folder under your CommandBox home. CommandBox manages this folder for you. You can change where the system Java installation go like so:
Search the AdoptOpenJDk API for available versions of Java for you to use.
You can filter the version, jvm, os, CPU arch, type, and release. Most of those parameters default to match your local system. For instance, running this command on Windows will only return Windows versions. To open up the search, pass nothing to that filter.
List the installed Java installations for you to start servers with. If you have set a global default Java version it will be marked in the list.
You may change the global default Java version for your servers with this command.
The ID follows the format from the Java endpoint. If the version you set as the default isn't installed yet, CommandBox will install it for you the next time a server starts or you can use the --install
flag.
You can pre-install a Java version so it's ready to go the next time you start a server with this command. This differs from the normal package install
command in that it doesn't install to the current working directory, but into the core server JRE folder that CommandBox manages for you. Use the --setDefault
flag to also set the newly installed Java version as the global default for all servers.
You can remove a java installation so it doesn't take up space on your hard drive. Use the FULL ID that shows in the java list
command to uninstall.
Note, the download will still be in your artifacts cache. Also, if you start a server up again that asks for a Java installation you've uninstalled, CommandBox will simply re-install it again.
Once you start using the embedded server for your development projects, you may wish to enable URL rewriting. Rewrites are used by most popular frameworks to do things like add the index.cfm
back into SES URLs.
You may be used to configuring URL rewrites in Apache or IIS, but rewrites are also possible in CommandBox's embedded server via a Tuckey servlet filter which uses an xml configuration.
Commandbox also exposes a way to do url rewrites with the Undertow predicate language. If you missed the Server Rules section, go there to learn how to do url rewrites, security, and http header modification in a nice text based language (non-xml).
Note: Tuckey-based URL rewrites are not recommended going forward. They are limited and do not play with with Multi-Site servers. It is recommended you move to the more-powerful Server Rules.
We've already added the required jars and created a default rewrite XML file that will work out-of-the-box with the ColdBox MVC Platform. To enable rewrites, start your server with the --rewritesEnable
flag.
http://tuckey.org/urlrewrite/manual/4.0/index.html
Now URLs like
can now simply be
In server.json
info The default rewrite file can be found in
~\.CommandBox\cfml\system\config\urlrewrite.xml
If you want to customize your rewrite rules, just create your own XML file and specify it when starting the server with the rewritesConfig
parameter. Here we have a simple rewrite rule that redirects /foo
to /index.cfm
customRewrites.xml
Then, fire up your server with its custom rewrite rules:
In server.json
You can place your custom rewrite rule wherever you like, and refer to it by using either a relative path or an absolute path. CommandBox will start looking relative to where the server.json
file resides.
or
If you're coming from Apache, Tuckey supports a large subset of the mod_rewrite
style rules like what you would put in .htaccess
. You can simply put your rules in a file named .htaccess
and point the web.rewrites.config
property to that file.
Note: The name of the file matters with mod_rewrite-style rules. It must be called .htaccess
. With xml rewrites, the filename is not important, only the content.
Here are some simple rewrite rules:
Please see the docs here on what's supported:
info For more information on custom rewrite rules, consult the Tuckey docs.
Your servers come ready to accept SES-style URLs where any text after the file name will show up in the cgi.path_info
. If rewrites are enabled, the index.cfm
can be omitted.
SES URLs will also work in a sub directory, which used to only work on a "standard" Adobe CF Tomcat install. Please note, in order to hide the index.cfm
in a subfolder, you'll need a custom rewrite rule.
The Tuckey Rewrite engine has debug and trace level logging that can help you troubleshoot why your rewrite rules aren't (or are) firing. To view these logs, simply start your server with the --debug
or --trace
flags. Trace shows more details than debug. These options work best when starting in --console
mode so you can watch the server logs as you hit the site. Alternatively, you can follow the server's logs with the server log --follow
command.
The Tuckey Rewrite library that CommandBox uses under the hood. It has some extra settings that CommandBox allows you to use.
To monitor your custom rewrite file for changes without needing to restart the server, use this setting.
To enable the inbuilt Tuckey status page, use the following setting. Note, debug
mode needs to be turned on for the Tuckey status page to work. Also, you'll need to customize your rewrite file if you use a path other than /tuckey-status
.
CommandBox allows you to create web aliases for the web server that are similar to virtual directories. The alias path is relative to the folder the server.json
lives in, but can point to any folder on the hard drive. Aliases can be used for static or CFM files.
Remember, relative paths configured in a JSON file (whether server.json
, or .site.json
, etc) will be resolved relative to the folder that the JSON file lives in!
To configure aliases for your server, create an object under web
called aliases
. The keys are the web-accessible virtual paths and the corresponding values are the relative or absolute path to the folder the alias points to.
Here's what your server.json
might look like.
Here's how to create aliases from the server set
command:
info On Adobe ColdFusion servers, .cfm files will be run automatically from inside an aliases directory. On Railo and Lucee servers, you'll need to create a CF mapping that maps the alias name and path for .cfm files to work.
For Multi-Site, web alias settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
The default welcome files are the usual index.cfm, index.htm, index.html, etc but you can override this with the welcomeFiles
setting in your server.json
by providing a comma-delimited list of files that you would like CommandBox to look for when a user hits a directory on a running server.
This setting is a complete override of the defaults, so you need to specify the full list.
By default, a CommandBox server will not show the contents of a directory that doesn't have an index file. You can enable directory browsing for a single server with
And you can enable it for all servers by default with
For Multi-Site, Welcome File settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
The web server in CommandBox is capable of enabling GZIp compression to reduce the size of HTTP responses. To enable GZip compress on your CommandBox server, add a web.gzipEnable
setting in your server.json
file.
By default GZip compression will be applied to any file over 1500 KB in size. This is because 1500 KB or smaller can fit inside a single network packet, so there's no real benifit in zipping small files and it just causes CPU overhead.
If you wish to customize the file size or any other aspect of when GZip compression is applied, you can specify a custom Undertow Predicate that, when true, will trigger GZip for the request.
Since ANY valid Undertow predicate language can be used here you can combined predicates to control exactly when GZip compression is applied. This example would apply GZip compression to any CSS files over 500 KB that were not in the /admin folder.
For Multi-Site, GZIP settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
The built in REST implementation in Adobe ColdFusion and Lucee is usually something you either love or hate. If you love it, you can enable it and customize the paths so it doesn't collide with your app's routes. if you hate it, you can turn it off. The REST servlet will be disabled unless you include a setting like so:
Note that the above setting will take over any URLs starting with /rest
or api
and you cannot use those routes or folders in your code. This is why it's handy to be able to modify or remove these. On a typical server, this is done via the web.xml
, but CommandBox will do it all for you with just the setting above.
Here are some settings for performance tuning your servers
This setting limits how many requests will be passed through the Undertow listener to your app server. It defaults to 30. Please note that your web server connector and Adobe ColdFusion may also have their own max request setting.
Or as a global setting for all servers:
Max Requests can NOT be set on a per-site basis since this setting controls the size of Undertow's worker task pool. You can, however, use the request-limit( 10 )
handler in a server rule that applies only to a specific site. Keep in mind, the maxRequests setting will still enforce an overall total running threads for all sites on a server.
CommandBox uses JBoss Undertow to power it's lightweight servlet containers. Undertow also powers JBoss Wildfly and has a lot of configurable options, not all of which have first-class CommandBox settings. These low-level settings come in two different categories:
Undertow Options - Settings that apply to the servlet and web server aspects of Undertow
XNIO Options - Part of the underlying XNIO library which powers all low-level I/O in undertow
Undertow has its own set of options which can be found here:
To set an XNIO option that CommandBox doesn't already expose with a first-class setting, you can set them into your server.json
like so:
You can also set global XNIO objects that will apply to all servers. Global options will be appended to server-level options.
XNIO (which is a refined version of NIO (Non-blocking I/O) has its own set of options that apply to the low level network transport functions it provides. You can find the full set of XNIO options here:
To set an XNIO option that CommandBox doesn't already expose with a first-class setting, you can set them into your server.json
like so:
You can also set global XNIO objects that will apply to all servers. Global options will be appended to server-level options.
The following JVM Args are supported when starting the embedded server.
You can set the max heap size the server is allowed to have (-Xmx
) by passing the heapSize
parameter to the start
command. This parameter defaults to megabytes but you can specify any valid suffix.
In server.json
You can set the starting heap size for the server (-Xms
) by passing the minHeapSize
parameter to the start
command. This parameter defaults to megabytes but you can specify any valid suffix.
In server.json
You can specify ad-hoc JVM args for the server with the JVMArgs
parameter.
In server.json
JVM args can also be set an array of strings which prevents you from needing to escape or quote anything.
Or via the CLI like so:
You can specify ad-hoc options for the underlying Runwar library using the RunwarArgs
parameter.
In server.json
Runwar args can also be set an array of strings which prevents you from needing to escape or quote anything.
Or via the CLI like so:
By default, the web server in CommandBox will follow the case sensitivity of the underlying file system. So, when on Windows /FiLe.TxT
will still load an actual file called /file.txt
. But on Linux, the case in the browser would need to match that of the file system. CommandBox allows you to force case sensitivity to be ON or OFF for a server, overriding the server's file system.
Note, this controls all access of static file, such as images, js, css, txt, etc as well as the initial lookup of .cfm files. It will also affect all internal usage of ServletContext.getRealPath( "/myPath.txt" )
. It will NOT affect CFML file operations such as <CFFile>
, <CFDirectory>
, fileRead()
, directoryList()
, etc. It will also not affect core CF engine functionality such as creating CFCs or cfincluding CFM templates. Any code directly accessing the file system will use the file systems case sensitivity. And creating CFC instance is never case sensitive in CFML.
There is a new setting called web.caseSensitivePaths
which has 3 possible values: true
, false
, or an empty string (default).
To force CommandBox's web server to be case sensitive, even on operating systems like Windows, use the following setting. There is a nominal performance benifit in doing this and can allow a Windows CommandBox server to mimic a Linux server for testing.
To force CommandBox's web server to be case insensitive, even on operating systems like Linux, use the following setting. There is a nominal performance overhead in doing this and can allow a Linux CommandBox server to mimic a Windows IIS server. In this mode, CommandBox will use an internal cache of file system lookups to improve performance. If there are two files of the same name using different case, then you will get whatever file is found first.
If you have custom jar files that you want to be available to a server, we recommend you use the this.javaSettings
functionality in your Application.cfc
to load those jars. If that isn't an option for you, or you want to include libs for a JDBC drivers then we offer a feature for you to specify a list of directories for which CommandBox will load jars from. This prevents you from worrying about getting your jars inside the WEB-INF/lib
which starts fresh anytime you forget a server.
To load in your jar files, the first method is to use the libDirs
parameter to the server start
command.
And the way to specify this in a portable manner in your `server.json` is like so:
Remember, paths to the start
command are relative to your current working directory and paths in your server.json
file are relative to the folder that the server.json
file lives in. Absolute paths work the same everywhere.
Have a bunch of servers and they ALL need the same jars, you can add your `libDirs` to the global server defaults config settings. Your global lib directories won't be overwritten by server-level config dirs, but instead appended to. Relative paths in your config settings are relative to the respective web root of the server. CommandBox will also ignore missing lib dirs to give you some flexibility in this.
For every server you start, there is a corresponding icon in your PC's system tray. In addition to the menu options you get out of the box, you can add in custom menu items. Menus are defined as nested arrays of structs, where each struct represents a single menu item. A menu item can be informational, have an action, or contain sub menus.
You can customize the tray menus for a server via 3 different methods:
The trayOptions
array in a specific server's server.json
file. These menu additions will be specific to that server.
The server.defaults.trayOptions
config setting. These menu additions will be added to every server you start
A custom CommandBox Module with an interceptor listening to the onServerStart
interception point that modifies the serverInfo.trayOptions
array.
Each menu item struct can have the following keys. Only label
is required.
label - This text appears on the menu and is the unique name
image - A custom image file to use for the icon. Relative paths in the server.json
will be relative to the JSON file Relative paths in the global config will be relative to the web root of the server.
disabled - Boolean that greys out menu item and disables any action. Use for informational items.
items - An array that contains a struct of sub menus.
action - This controls what the menu item does when clicked. Possible options are:
openfilesystem - Opens a folder on the file system. Requires path
to be set as well.
openbrowser - Opens a URL in your default browser. Requires url
to be set as well.
stopserver - Stops the current server
run - Runs an arbitrary native command synchronously. Requires command
to be set as well.
runAsync - Runs an arbitrary native command asynchronously Requires command
to be set as well.
runTerminal - Runs an arbitrary native command in a new Terminal window. Requires command
to be set as well.
path - The file system path to use for the openfilesystem
action.
url - The HTTP URL to use for the openbrowser
action
command - The native command to run for the run
, runAsync
, or runTerminal
actions.
workingDirectory - The working directory to use for the run
, runAsync
or runTerminal
actions.
shell - Override the native shell to use on your OS. Defaults to your nativeShell
config setting.
Commands executed by the run
action will display their output in a popup window. The PID of the process is available if running on Java 9 or later. Also, there is a button to kill the process, but your mileage may vary. Only use this option to run command line apps that have console output you want to see.
Commands executed by the runAsync
action work like the run
action except there is no windows to show you the output. This is what you want to use to fire off an app such as an IDE.
Commands executed by the runTerminal
action work like the run
action except a new terminal window is opened to run the command. The terminal windows stays open and you can continue to interact with it when the command finishes.
You can customize how your command is run by setting the optional workingDirectory
and shell
properties. If not set, the working directory will be the web root of the server.
You can nest menus by supplying another array of structs in the items
property of a menu. A menu cannot have an action and have sub menus.
Menu items are layered "on top" of existing options whichs mean you can add new sub menu items to an existing top level menu. You can even override the action or image of a built-in menu. Menu items are registered in this order:
Built-in menus
Config setting server defaults
server.json trayOptions
onServerStart interceptor
This example server.json
will add a new sub menu into the existing "Open..." top level menu.
There is no way to remove existing menu items via your config settings or server.json
. To do that, you'd need to directly manipulate the trayOptions
array in an interceptor.
You've always been able to add ad-hoc Java system properties for a server in your server.json
via jvm.args
in the format of -Dfoo=bar
. There is also a top-level struct that is more readable which does the same thing:
No additional quoting or escaping is needed for spaces or special characters when using this method.
Set these programmatically like so:
Or set them globally for all servers in your config setting server defaults.
Keys will be merged, giving precedence to the server.json
values.
There are many ways to pass environment variables into a server. You can set them in your actual OS shell before starting box, set them as CommandBox env vars, use the commandbox-dotenv
module to read them from a .env
file or many Docker-based options. Just in case you wanted one MORE way to do it, you can also set env vars directly in your server.json
file.
These env vars will not be visible in the CommandBox shell like a .env
file is, but will be used exclusively when starting the server. They will be visible inside the running server and also present in CommandBox to any interception points or CFConfig while the server is starting.
Note the two CFConfig examples above do the same thing (assuming you have commandbox-cfconfig
installed. Any nested keys will be concatenated with underscores when the actual env var is set. Therefore the cfconfig
key and nested requestTimeout
key will create an env var actually called cfconfig_requestTimeout
when the server starts. This is simply a convenience to help you group together related env vars with a matching prefix.
You can see that the web.http.port
is using an env var from the env
block above it. All env vars in the env
block will be added to CommandBox's environment BEFORE the rest of the JSON file is expanded. Env vars in the env
block can ALSO reference other pre-existing env vars. In the example above, ${brad}
is assuming there is a pre-existing env var of that name set outside this file.
In case anyone is wondering, it's actually possible to override your server.json
settings from inside the env
block like so:
but we can't imagine why you'd ever want to do that :) That would be the equivalent of setting the following env vars outside of CommandBox:
For , web server case sensitivity can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
When you start a CF server in CommandBox, the default behavior is that the WAR for that version is expanded into a folder inside the server
directory inside your CommandBox home. There is a sub folder containing an MD5 hash of the server name and web root concatenated with the server name. Inside of that, is a folder containing the name of the CF Engine followed by the engine version. The result is something like this:
When you start a new version of the CF engine, the old folder is left in place, and a new one is created containing the new WAR. e.g.
This allows you to easily revert back to the previous version as CommandBox automatically handles the server homes for you. Running server forget
will remove the entire top level folder containing all the engine versions.
When you start a new server version to replace a previous version, you will get a new server home which also means all settings and manual changes to the old server home will not exist in the new one. if you have commandbox-cfconfig
installed, it will automatically copy over all CF config settings that it can handle into the new server home. Any other custom changes you've made such as license files, logs, jars or web.xml
modifications will not be brought over.
You can move the server home to a custom folder of your choice with the following setting:
Note, the relative path is relative to the folder that the server.json
lives in. This can give you a predictable server home, but comes with a few caveats:
CommandBox will NOT auto-upgrade new versions of the CF engine
If you ask for a new version of the engine, CommandBox will ignore it
You must server forget
and remove the server home before you can start a new server in your custom server home.
There is an option that will give you a mix of a custom server home and the default behavior where the server home is automatically placed inside the CommandBox home. This is the app.singleServerHome
setting. It defaults to false
.
This will create a folder similar to the default behavior above, but WITHOUT the version number appended to the folder name. An example server home would be:
This has the convenience of auto-managing the server home for you, but still come with all the caveats listed above for a custom server home such as requiring you to server forget
to upgrade or change versions via CommandBox.
This setting is a CLI-wide config setting that forces CommandBox to only have a single server. This setting was created to simplify our Ortus Docker Images and you likely DON'T want to use this outside of a scenario such as a Docker image where only one server exists. When this is enabled, the first server that is started will be remembered as the only serer that exists. No matter what directory you run start
and stop
commands from and no matter what name
you pass, CommandBox will always perform that action against the single server it has. You can server forget
and start another server elsewhere, but there can only be one server at a time. This setting was added to help prevent duplicate servers from getting created in different folders during Docker builds which mixed up the settings.
Adobe ColdFusion 2021 and later have a built in command in their server home called cfpm
(ColdFusion Package Manager) used to install modules into the core of the ACF engine.
CommandBox provides a passthrough command called cfpm
which will locate the Adobe server and invoke the correct cfpm.bat or cfpm.sh script, passing along whatever arguments you've typed.
The CommandBox cfpm
command will use the current working directory of the shell, or intercept data, if run from inside of a package script or server script to figure out which server to apply to. It will also ensure the JAVA_HOME
env var is set for the process.
If you need to force cfpm
to act upon a specfific CommandBox server, set the following env var before running it:
You can also load packages using server.json
and calling cfpm
as a script:
More information about scripts can be found in Server Scripts
CommandBox adds a /cf_scripts/scripts
alias for you any time you start an Adobe CF server. This alias points to the same folders in the root of the Adobe WAR. If you set a custom scripts src path in the CF administrator then you'll want to ensure CommandBox uses the expected alias.
There is a setting called web.adobeScriptsAlias
which allows you to control the public, web-accessible path to the scripts folder that CommandBox creates for you.
For Multi-Site, Adobe's Script Alias settings can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
If you want to entirely disable the Adobe script alias, you can set that setting to an empty string.
If you're using CFConfig as well to manage your Adobe CF configuration, note that CFConfig is smart enough to adjust automatically to this setting.
If a web.adobeScriptsAlias
is set in CommandBox and there is not a custom CFConfig setting, then the same alias will be set into ACF via CFConfig.
If CFConfig has a custom CFFormScriptDirectory
setting but CommandBox doesn’t have a custom adobeScriptsAlias
setting, then default CommandBox’s alias to be the one set in CFConfig.
So basically, you can set the script directory either in CFConfig or in your server.json
and the other will follow suite with no additional effort.
CommandBox uses a custom resource manager in Undertow to resolve "real" paths (relative) in the servlet context with the path on the file system (absolute). This includes log concerning where the root of the WAR is, where the CF engine web root is, and any web aliases. The resource manager is responsible for not only resolving paths to CF files, but also static files being sent by CommandBox's web server.
You can activate a cache for all file path resolution in the resource manager by activating this setting. This is only for production and will eliminate repeated file system hits by your CF engine, such as checking for an Application.cfc file on every request, or testing where the servlet context root is. This will NOT affect any of the CFML fileRead()
sort of commands or any code in the CF engine that bypasses the ServletContext
and directly hits the file system. The default is false
when the profile
is not production.
Standard Adobe ColdFusion installations have a similar cache of "real" paths from the servlet context that is tied to a setting in the administrator called "Cache Webserver paths" but that setting is not available and does not work on CommandBox servers for some reason.
If you enable the cache, but set the max size to 0
that will cache the file system lookup still (like Adobe's setting) but will not cache the actual contents of files.
There is an XNIO file system watcher started for the web root and any virtual directories in your server. This change listener serves two purposes:
Cache invalidation for the servlet path lookup matching
Cache invalidation for welcome file lookups
In normal operations you should have no issues with this, but it has been observed starting a server in a web root with a very large number of files (like over 200,000) can consume a lot of resources, and even cause out of memory errors. The change listener in Undertow is disabled by default and can be enabled with this setting:
Some servers (typically Linux) have a "send file" capability which allows a program to use the kernel to directly transfer a file across a port without needing to transfer all the bytes of that file through the application's memory space. Java is capable of tapping into this behavior via the FileChannel
class and it has great performance boost when serving up large files via the web server, which now no longer need to have all the bytes of the file read into Java's heap.
CommandBox will enable send file capability by default, but it's dependant on your server operating system and file system as to whether it will kick in. You can control the threshold for how big a file needs to be before Undertow will use the send file capabilities.
Which creates the following config:
You can disable the send file feature entirely by setting web.sendFileMinSizeKB
to -1
.
If you enable a --debug
or --trace
server start, it is possible to get additional low-level information in the logs about every single file path that is resolved through the servlet context's resource manager. This logging is disabled by default since it is quite verbose.
Or in the server.json
as:
For Multi-Site, Resource Manager Logging can be configured on a per-site basis in the sites
object of the server.json
or in a .site.json
file.
Every server setting can be overridden by convention by creating environment variables in the shell where you run box
. This is idea for CI builds were you want to easily set ports, or tweak settings for your build. You set set these as actual environment variables or Java system properties of the CLI.
The var must start with the text box_server_
and will be followed by the name of the setting.
For nested settings inside of a struct or array you can use underscores to represent dots.
The overrides are applied using the same mechanism that the config set
command uses, which means you can also pass JSON directly for complex values.
On OS's like Windows which allow for any manner of special characters, you can provide any string which would also be valid for the config set
command. Ex:
When you provide JSON, the append
flag will be set to true when adding the configuration to what's already in CommandBox.
Overridden env vars will not be written to the server.json
file and will be lost when box stops. They will also take precedence and override any explicit server.json
settings already set but will NOT override actual parameters to the server start
command.
When you start an Adobe or Lucee CF Engine, the WAR CommandBox uses has a stock web.xml
baked into it. Sometimes you may want to add custom servlets, servlet mappings, etc into your server. You can override the stock web.xml
in part or in total with a file of your own which you specify in the server.json
like so:
The path can be absolute or relative to the server.json
file. CommandBox will still load the default web.xml
from the CF engine, and then it will load your override file on top of the previous settings. This means additional items in your override will be merged into the existing settings, and servlets with the same name as existing default servlets will be completely overridden and replaced.
Here is a list of all the top level items CommandBox will look for in your web.xml
file:
Servlets
Servlet mappings
Servlet filters
Server filter mappings
Listeners
Context params
welcome files (only if not in server.json)
error pages (only if not in server.json)
mime types
session config
So if you wanted to replace the default servlet mapping for a Lucee server to also process .html
files, you could use an override file like this:
The default behavior is to add or update existing configurations. If you want to remove a servlet or listener from the base file, you can enable the app.webXMLOverrideForce
flag.
This will completely remove any configuration from the web.xml
that is explicitly provided in your override file. For example, if the default web.xml
specifies two servlet filters and you provide an override web.xml
with one servlet filter and the force flag is true, both of the default servlet filters will be removed in favor of your one servlet filter from your override file.
If you need something more complex than this-- e.g. simply removing default settings without replacing them, you'll need to create a custom CF engine with a default web.xml
of your own design.
Every time you start a server, the settings used to start it are saved in a server.json
file in the web root. Any parameters that aren't supplied to the start
command are read from this file (if it exists) and used as defaults. Here are the possible properties for a server.json
file:
/server.json
CommandBox is designed to allow you to start, stop, and manage as many servers as you like. However, when using CommandBox in an environment such as Docker containers where you only ever want to have a single server, this can cause issues where warming up the server with different names creates more than one server. You can enable Single Server Mode which will only allow CommandBox to have a single server that shows when you run the server list
command.
This is a global setting that takes immediate effect. If you already have more than one server defined, it will not remove the extra ones, it will simply re-use the first server it finds. In this mode, the server name becomes essentially meaningless. Each of these commands would use the same default server
Note, as of CommandBox 6, the old format of experimental Runwar args that look like --name-here
is removed. There is a new syntax for specifying arbitrary experimental flags.
There are not any experimental features in CommandBox, but you can influence the JSON file used to configure runwar with the following syntax.
The struct you specify will be merged into the JSON file that is sent to Runwar. Note, this JSON format is undocumented and subject to change.
CommandBox servers use Log4j to process the console logs for a server. The console logs contain
Debugging output from CommandBox
Logging from any Java libraries in use such as Lucee or Undertow
Output from Lucee's systemOutput()
BIF
Output from <cfdump var="foo" output="console">
Output from LogBox's Console Appender
This output is visible in the "standard out" for the actual Runwar java process, which is what you see in Docker container logs, or if you start your server with the --console
flag. The output is also written file a file appender to the server.out.txt
log file inside the CommandBox server home, which is what the server log
command uses.
By default Log4j's console and file appender use a PatternLayout
with a default pattern of
The Log4j docs explain what valid placeholders exist
You can choose a custom pattern for the pattern layout. This example would put the date/time into every log message:
This example would log ONLY the message with no severity or category:
Note, the color coding of log lines in CommandBox is dependent upon the default Log4j pattern layout.
If you want, you can change the entire appender layout itself to be something other than the PatternLayout
. Log4j supports a number of appender layouts plus is configurable with layouts of your own creation, so long as they are visible on the classpath. All of the Log4j 2.x appender layouts are avilable for you to use as well as the JSONTemplateLayout
which we also bundle.
You can view all the built in layouts here:
Common options are:
HTMLLayout
JSONTemplateLayout
XMLLayout
CsvLogEventLayout
Rfc5424Layout
Specify the layout like so:
Any settings specific to a layout can be set just like the pattern option above.
Please refer to the Log4j docs to find what the valid options are for a given appender layout.
Note: some of the built in layouts require additional jars which do not ship with CommandBox. You will, need to download these jars separately and specify them to the app.libDirs
setting so they are visible to the class loader. For example, the CSV layout requires the Apache Commons commons-csv
library which you would specify like so:
When using CommandBox on a staging or production server, you may wish to start up servers as a service when the OS comes online. The recommended approach is to use the CommandBox Service Manager Module, which is a commercial module that handles all major operating systems (Linux, Mac, Windows) automatically.
See screencast here:
Alternatively, you can manually do so following one of these community guides.
See screencast here: https://www.ortussolutions.com/blog/screencast-starting-commandbox-servers-as-a-windows-service
Coming soon...
Create a .service
file
as follows:
Start the service
Give the service about a minute to load up, then check its status
Once you've verified the service is running as expected, enable the service to load at boot
Interacting with the server.json
file uses the commands server set
, server show
, and server clear
, which work the same as the package set/show/clear
commands.
Set the port for your server:
View the port:
View the port with JMESPath:
Remove the saved setting:
server.json
allows you to package up an app that requires special start settings such as rewrites, JVM args, or heap size, and anyone can run it with the same settings you do by simply typing server start
. Make sure to not deploy the server.json
file to your production server where it may be web-accessible.
server.json
outside the web rootTo help with this, you can store your server.json
file outside of the web root and use the web.webroot
property in it to point to the location of the web root. This can be an absolute path or a relative path to the location of the JSON file.
When you start the server, you can run the start
command from the same directory that the server.json
file lives, or specifiy the path to the JSON file like so:
If there is no web root in your server.json
, CommandBox will use the folder that the JSON file is stored in. If there is no JSON file at all, the current working directory is used.
With the advent of , you may want to regularly start up the same web site with different settings (such as different CF engine's). To help with this, you can have more than one JSON file.
anything.json
The default server configuration file is server.json
, but you can actually call the file anything you want as long as you use the file's path (or unique name) when starting the server.
Let's say we want to test our app in Lucee 4, Lucee 5 and Adobe 2016. Let's start 3 servers. Note we give each server a unique name. This will come in handy when we want to start/stop the servers by name later.
Info It's important to always use a name when starting more than one server. Otherwise, the settings will override each other and only the last server will be saved. Also, you will only be able to stop the last server via the
stop
command.
You can have full control over the name of the JSON files by using the serverConfigFile
parameter, but when CommandBox sees us use the name
parameter, it will automatically create a file called server-{name}.json
. In this case, we'll have 3 new files:
server-lucee4.json
server-lucee5.json
server-adobe2016.json
If you run the server show
command, you'll see it returns {}
. This is because it looks for a file called server.json
by default. Not to worry, you can still programmatically manipulate your JSON files like so:
Info The property name and server config file path are interchangeable for the
server show
andserver clear
commands for your convenience.
Now that you have 3 JSON files-- one for each server, you can use the path to the JSON file (absolute or relative to your CWD) to control each server.
For your convenience, if you pass in a path to an existing JSON for the server name, we'll use it as the serverConfigFile
parameter.
This trick works on any server
commands
After you've started a server at least once, you can use its server name to control it as well which is a great shortcut. CommandBox will recognize the server name and remember where the server JSON for that server name is stored. Then it will pull the correct web root from the JSON file.