Deploying without CFML Source Code
Deploying without CFML Source Code
Lucee has no cfencode tool, but there are two ways to deploy an application without readable CFML source:
compileToBytecode()(Lucee 8) replaces each.cfm,.cfcand.cfsfile with its compiled bytecode, in place. Lucee detects that the file contains bytecode and executes it directly.- Sourceless archives (
.lar) package a mapping as compiled classes only. See Lucee Archives (.lar files).
Both deploy compiled code instead of source.
Compile in place with compileToBytecode()
compileToBytecode( path [, keepSource] [, privateKey] [, recursive] ) compiles a single file, or a whole directory, and writes the bytecode back over the original file.
| Argument | Default | Description |
|---|---|---|
path |
required | Relative or absolute path to a CFML file or a directory |
keepSource |
false |
When true, the source is copied to a dot-prefixed file next to the template (index.cfm becomes .index.cfm) |
privateKey |
none | RSA private key used to encrypt the bytecode, see "Encrypting the bytecode" below |
recursive |
true |
When path is a directory, also process subdirectories |
It returns a struct with the keys compiled, skipped, errors and warnings. Errors are collected per file, so one failing template doesn't stop the rest. Dot-prefixed files, files that aren't CFML (by extension), and files that already contain bytecode are skipped, so running it again is safe.
// build step, run on a copy of your application, never on the only copy of your source
result = compileToBytecode( path="/build/myApp", keepSource=false );
systemOutput( "compiled: #result.compiled.len()#, skipped: #result.skipped.len()#, errors: #result.errors.count()#", true );
Deploy the resulting directory as usual. When a request hits index.cfm, Lucee sees that the file contains bytecode and runs it, no source needed.
Things to be aware of:
- The source is replaced. Unless you use
keepSource=true, the original is gone, so keep your source in version control and compile a copy in your build. - Compilation can produce auxiliary classes (for example for Java code in functions) that are stored in the
cfclassesdirectory. Whenwarningsreports this, deploy thecfclassesdirectory together with the templates. - Bytecode is only executed when it isn't blocked. The system property
lucee.compiler.block.bytecode(environment variableLUCEE_COMPILER_BLOCK_BYTECODE) controls this and defaults tofalse, so bytecode runs. If a server has it set totrue, direct execution of compiled.cfm,.cfcand.cfsfiles is refused. See Environment Variables / System Properties for Lucee. - A compiled
.cfmcan't be used as a component and a compiled.cfccan't be used as a regular template. Lucee throws an exception if the file type doesn't match.
Encrypting the bytecode
Pass an RSA private key as privateKey to encrypt the bytecode when compiling. The matching public key must be available on every server that runs the code, as the PUBLIC_KEY environment variable or as the PUBLIC_KEY system property. Without it, executing an encrypted template fails with an exception that says so.
result = compileToBytecode( path="/build/myApp", privateKey=privateKey );
Both keys are Base64 encoded RSA keys: the private key in PKCS#8 format and the public key in X.509 format.
Restoring the source
If you compiled with keepSource=true, restoreToSource( path [, recursive] ) puts the source back. It replaces the bytecode with the content of the dot-prefixed file and deletes that file. It returns a struct with the keys restored, skipped and errors.
compileToBytecode( path="/build/myApp", keepSource=true );
// later, on the same directory
restoreToSource( path="/build/myApp" );
Sourceless archives
A Lucee archive (.lar) can be built with addCFMLFiles="false", so it contains only the compiled classes and none of the .cfm / .cfc source. This works in all Lucee versions that support archives and also covers component and custom tag mappings. The full workflow for creating and deploying archives is described in Lucee Archives (.lar files).
Which one to use
- Use
compileToBytecode()when you want to keep your normal directory layout and deploy a directory tree, or when you want to encrypt the code. - Use an archive when you want a single file per mapping, or when you need this on a Lucee version before 8.
If you only want to avoid compilation on the production server, but don't need to hide the source, see Precompiled.