Runtime Providers
LuCLI supports multiple runtime providers for running your CFML applications. This guide helps you choose the right runtime for your needs and shows you how to configure each option.
Available Runtimes
| Runtime | Best For | Lucee Version | Setup Complexity |
|---|---|---|---|
| Lucee Express (default) | Development, quick start | Any | None |
| External Tomcat | Production, enterprise | 7.x for Tomcat 10+, 6.x for Tomcat 9 | Medium |
| Docker (experimental) | Containers, CI/CD | Determined by image | Low |
Lucee Express (Default)
Lucee Express bundles Tomcat and Lucee together in a single download. This is the default runtime and requires no configuration.
When to Use Lucee Express
- Development environments - Quick to start, no setup required
- Learning CFML - Get started immediately
- Simple deployments - Self-contained, easy to manage
- Prototyping - Spin up servers quickly
Configuration
No runtime section needed - Lucee Express is the default:
{
"name": "my-app",
"lucee": {
"version": "6.2.2.91"
},
"port": 8080
}
Or explicitly specify it:
{
"name": "my-app",
"lucee": {
"version": "6.2.2.91"
},
"port": 8080,
"runtime": {
"type": "lucee-express",
"variant": "standard"
}
}
Variants
Lucee Express comes in three variants:
| Variant | Description | Use Case |
|---|---|---|
standard |
Full Lucee distribution (default) | Most applications |
light |
Reduced size, fewer extensions | Smaller footprint |
zero |
Minimal install, extensions on demand | Microservices, containers |
{
"runtime": {
"type": "lucee-express",
"variant": "light"
}
}
External Tomcat
Use an existing Tomcat installation with Lucee deployed separately. This gives you full control over Tomcat configuration and allows sharing a single Tomcat installation across multiple projects.
When to Use External Tomcat
- Production environments - Battle-tested Tomcat with your hardening
- Enterprise deployments - Align with IT policies and existing infrastructure
- Tomcat expertise - Leverage existing Tomcat knowledge
- Shared Tomcat instances - Run multiple apps on one Tomcat
- Custom Tomcat configuration - Use your own server.xml, security settings, etc.
Version Compatibility
Important: Tomcat and Lucee versions must be compatible:
| Tomcat Version | Servlet API | Compatible Lucee |
|---|---|---|
| 9.x and below | javax.servlet | Lucee 5.x, 6.x |
| 10.x, 11.x | jakarta.servlet | Lucee 7.x |
LuCLI automatically detects the Tomcat version and validates compatibility. You'll see an error if versions don't match:
❌ Lucee 6.2.2.91 is not compatible with Tomcat 11
Tomcat 10+ uses jakarta.servlet (Jakarta EE), but Lucee 6.x uses javax.servlet (Java EE).
Solutions:
1. Use Lucee 7.x with Tomcat 11 (recommended)
2. Use Tomcat 9.x with Lucee 6.2.2.91
Configuration
{
"name": "my-app",
"lucee": {
"version": "7.0.1.100-RC"
},
"port": 8080,
"runtime": {
"type": "tomcat",
"catalinaHome": "/opt/tomcat"
}
}
Using Environment Variables
You can reference the CATALINA_HOME environment variable:
{
"runtime": {
"type": "tomcat",
"catalinaHome": "${CATALINA_HOME}"
}
}
If catalinaHome is not specified, LuCLI falls back to the CATALINA_HOME environment variable.
How External Tomcat Works
LuCLI uses the CATALINA_BASE pattern to keep your Tomcat installation pristine:
CATALINA_HOME (your Tomcat install - untouched)
├── bin/
├── lib/
└── conf/
CATALINA_BASE (~/.lucli/servers/<name>/)
├── conf/
│ ├── server.xml ← Patched with ports/context
│ └── web.xml ← Lucee servlets added, JSP removed
├── lib/
│ └── lucee-*.jar ← Lucee JAR deployed here
├── bin/
│ └── setenv.sh ← JVM options from lucee.json
├── logs/
├── lucee-server/
└── lucee-web/
Benefits:
- Your Tomcat installation is never modified
- Each project has isolated configuration
- Easy to upgrade Tomcat independently
- Multiple Lucee versions can coexist
What LuCLI Configures
When using external Tomcat, LuCLI automatically:
- Copies and patches server.xml - Sets ports and adds your webroot as a context
- Patches web.xml - Adds Lucee servlets (CFMLServlet, RESTServlet)
- Removes JSP servlets - Not needed for CFML, reduces attack surface
- Deploys Lucee JAR - To CATALINA_BASE/lib
- Generates setenv scripts - JVM options from your lucee.json
- Protects lucee.json - Adds security constraint to block HTTP access
Environment-Specific Runtimes
You can use different runtimes per environment:
{
"name": "my-app",
"lucee": {
"version": "7.0.1.100-RC"
},
"port": 8080,
"environments": {
"dev": {
"runtime": {
"type": "lucee-express"
}
},
"prod": {
"runtime": {
"type": "tomcat",
"catalinaHome": "/opt/tomcat"
}
}
}
}
# Development - uses Lucee Express
lucli server start --env dev
# Production - uses external Tomcat
lucli server start --env prod
Docker (Experimental)
Run your CFML application inside a Docker container using the official lucee/lucee image. LuCLI manages the container lifecycle so server start, server stop, server status, and server list all work as expected.
Note: Docker runtime is experimental and may not cover all image variants or advanced Docker configurations yet.
When to Use Docker
- Container-based workflows - CI/CD pipelines, Kubernetes, Docker Compose
- Consistent environments - Same image in dev and production
- Isolation - No local Java or Tomcat installation required
- Quick experimentation - Try different Lucee versions via image tags
Prerequisites
- Docker must be installed and running on your machine
- The
dockerCLI must be available on yourPATH
Configuration
The simplest form — just set the runtime to "docker":
{
"name": "my-app",
"port": 8380,
"runtime": "docker"
}
Or with more control:
{
"name": "my-app",
"port": 8380,
"runtime": {
"type": "docker",
"image": "lucee/lucee",
"tag": "6.2.2.91",
"containerName": "my-custom-name"
}
}
Runtime Options
| Key | Default | Description |
|---|---|---|
runtime.image |
lucee/lucee |
Docker image to use. |
runtime.tag |
latest |
Image tag / version. |
runtime.containerName |
lucli-{name} |
Docker container name. Defaults to lucli- followed by the server name. |
How It Works
When you run lucli server start with a Docker runtime:
- LuCLI removes any stale container with the same name
- Runs
docker run -dwith:- Port mapping: your configured
port→ container port 8888 - Volume mount: your project directory →
/var/www(the Lucee webroot)
- Port mapping: your configured
- Waits for the server to become available on the mapped port
- Tracks the container via a
.docker-containermarker file
server stop sends docker stop followed by docker rm. server status and server list check the container state via docker inspect.
Environment Variables
LuCLI passes several environment variables to the container automatically:
LUCEE_ADMIN_PASSWORD— fromadmin.passwordinlucee.jsonLUCEE_EXTENSIONS— from your dependency lock file- Any custom variables defined in
envVarsinlucee.json
Choosing an Image Tag
The lucee/lucee image publishes tags for specific versions:
{"runtime": {"type": "docker", "tag": "6.2.2.91"}}
Use latest for the most recent stable release, or pin to a specific version for reproducibility.
Limitations
- Foreground mode (
server run) is not yet supported for Docker — servers always start in the background - The server instance directory is not mounted into the container (Tomcat configuration inside the container is managed by the image)
- Advanced Docker options (networks, extra volumes, resource limits) are not yet configurable via
lucee.json
URL Rewriting
LuCLI uses Tomcat's built-in RewriteValve for URL rewriting, which works across all Tomcat versions (8–11) with no javax/jakarta compatibility issues.
{
"urlRewrite": {
"enabled": true,
"routerFile": "index.cfm"
}
}
Rewrite rules use Apache mod_rewrite syntax and are deployed to conf/Catalina/<hostName>/rewrite.config in the server's CATALINA_BASE. When both HTTPS redirect and URL rewriting are enabled, rules are combined into a single rewrite.config file.
For full details, see URL Rewriting.
⚠️ Migration Notice: The previous Tuckey UrlRewriteFilter (
urlrewrite.xml) has been replaced. If your project usesurlrewrite.xml, LuCLI will display a deprecation warning at startup. See the migration guide for details.
Jetty Runtime
URL rewriting is not supported with the Jetty runtime. If urlRewrite.enabled is set to true, LuCLI will display a warning and skip URL rewrite configuration.
Choosing the Right Runtime
Decision Flowchart
Start
│
├─► Development/Learning? ──► Lucee Express
│
├─► Need specific Tomcat version/config? ──► External Tomcat
│
├─► Production with existing Tomcat? ──► External Tomcat
│
├─► Container-based / CI/CD workflow? ──► Docker
│
├─► Simple deployment, self-contained? ──► Lucee Express
│
└─► Enterprise IT policies require Tomcat? ──► External Tomcat
Quick Comparison
| Feature | Lucee Express | External Tomcat | Docker |
|---|---|---|---|
| Setup time | Instant | Requires Tomcat install | Requires Docker |
| Tomcat version | Bundled | Your choice | Determined by image |
| Tomcat customization | Limited | Full control | Via Dockerfile |
| Lucee/Tomcat coupling | Tied together | Independent | Managed by image |
| Multiple apps | Separate instances | Can share | Separate containers |
| Production hardening | Basic | Your configuration | Image-based |
| Upgrade path | Replace download | Upgrade independently | Change image tag |
Migration Between Runtimes
From Lucee Express to External Tomcat
- Install Tomcat 10+ (for Lucee 7.x) or Tomcat 9 (for Lucee 6.x)
- Update
lucee.json:
{
"lucee": {
"version": "7.0.1.100-RC"
},
"runtime": {
"type": "tomcat",
"catalinaHome": "/opt/tomcat"
}
}
- Stop and recreate the server:
lucli server stop
lucli server start --force
Your application code doesn't change - only the runtime configuration.
Troubleshooting
"Lucee X.x is not compatible with Tomcat Y"
Check the version compatibility table above. Update either your Lucee version or use a different Tomcat installation.
Server starts but CFML doesn't work
- Check the server logs:
lucli server log --type server - Verify Lucee JAR was deployed:
ls ~/.lucli/servers/<name>/lib/ - Check web.xml has Lucee servlets:
grep CFMLServlet ~/.lucli/servers/<name>/conf/web.xml
Port conflicts
The external Tomcat's ports are controlled by LuCLI, not your Tomcat's default server.xml. Check your lucee.json port settings.
Docker: Container starts but pages don't load
- Check the container is running:
docker ps --filter name=lucli-<name> - Check container logs:
docker logs lucli-<name> - Verify your project directory is mounted:
docker exec lucli-<name> ls /var/www/
Docker: "container name already in use"
LuCLI automatically cleans up stale containers before starting. If you see this error, the container may have been created outside of LuCLI. Remove it manually:
docker rm -f lucli-<name>