wheels docker init
Initialize Docker configuration for your Wheels application with support for multiple databases, CF engines, production mode, and Nginx reverse proxy.
Synopsis
wheels docker init [options]
Description
The wheels docker init
command creates Docker configuration files for containerizing your Wheels application. It generates a Dockerfile
, docker-compose.yml
, .dockerignore
, configures datasources in CFConfig.json
, and optionally creates Nginx configuration for reverse proxy support.
Options
--db
Database system to use
mysql
h2
, mysql
, postgres
, mssql
--dbVersion
Database version to use
varies by db
Any valid version for the selected database
--cfengine
CFML engine to use
lucee
lucee
, adobe
--cfVersion
CFML engine version
6
Any valid version for the selected engine
--port
Custom application port (overrides server.json)
from server.json or 8080
Any valid port number
--force
Overwrite existing Docker files without confirmation
false
true
, false
--production
Generate production-ready configuration
false
true
, false
--nginx
Include Nginx reverse proxy
false
true
, false
Default Database Versions:
MySQL:
8.0
PostgreSQL:
15
MSSQL:
2019-latest
H2: embedded (no version needed)
Examples
Basic initialization (MySQL with Lucee 6)
wheels docker init
Initialize with PostgreSQL
wheels docker init --db=postgres
Initialize with specific database version
wheels docker init --db=postgres --dbVersion=13
Initialize with Adobe ColdFusion
wheels docker init --cfengine=adobe --cfVersion=2023
Initialize with H2 embedded database
wheels docker init --db=h2
Custom port
wheels docker init --port=3000
Force overwrite existing files
wheels docker init --force
Production configuration
wheels docker init --production
Production with Nginx reverse proxy
wheels docker init --production --nginx
Development with Nginx on custom port
wheels docker init --nginx --port=8080
Full custom configuration
wheels docker init --db=postgres --dbVersion=15 --cfengine=lucee --cfVersion=6 --port=8888 --production --nginx
What It Does
Checks for existing files (unless
--force
is used):Detects existing
Dockerfile
,docker-compose.yml
, and.dockerignore
Prompts before overwriting existing Docker configuration
Lists all files that will be replaced
Allows cancellation to prevent accidental overwrites
Creates Dockerfile optimized for CFML applications:
Development mode (default):
Hot-reload enabled
Development tools installed (curl, nano)
Source code mounted for live updates
BOX_INSTALL=TRUE
for automatic dependency installation
Production mode (
--production
):Security hardened with non-root user (UID 1001)
box install --production
for optimized dependenciesHealth checks configured (30s interval, 10s timeout, 3 retries)
Production environment variables set
No source volume mounts
Optimized image size
Based on
ortussolutions/commandbox:latest
Installs H2 extension for Lucee if H2 database selected
Exposes application port (custom, from server.json, or defaults to 8080)
Generates docker-compose.yml with:
Application service with port mapping or internal exposure
Database service (mysql, postgres, or mssql) if selected
Nginx reverse proxy service (if
--nginx
)Environment variables for database connection
Volume mappings for data persistence
Development mode: Source code mounted for hot-reload, development command
Production mode: No source mounts,
restart: always
policies
Creates Nginx configuration (if
--nginx
):Reverse proxy to application backend
Load balancing ready upstream configuration
WebSocket support with upgrade headers
Static asset caching with 1-day expiration
Custom upload size limits (100MB)
Health check endpoint at
/health
Production mode only:
Security headers (X-Frame-Options, X-Content-Type-Options, X-XSS-Protection, Referrer-Policy)
Gzip compression for text content types
Port configuration:
Development: Nginx on port 8080
Production: Nginx on port 80
Creates .dockerignore excluding:
.git
and.gitignore
node_modules
.CommandBox
server.json
logs
and*.log
tests
.env
Production mode only: README files, IDE configs (
.vscode
,.idea
),.DS_Store
Updates CFConfig.json:
Configures
wheels-dev
datasource for selected databaseSets up proper JDBC drivers and connection strings:
MySQL:
com.mysql.cj.jdbc.Driver
PostgreSQL:
org.postgresql.Driver
MSSQL:
com.microsoft.sqlserver.jdbc.SQLServerDriver
Uses Docker service name
db
for host resolutionConfigures appropriate ports and credentials
Updates server.json for Docker compatibility:
Sets
web.host
to0.0.0.0
(required for Docker containers to accept external connections)Sets
openBrowser
tofalse
(Docker containers have no GUI)Configures port from
--port
argument, existing server.json, or defaults to 8080Sets CFEngine version (e.g.,
lucee@6
oradobe@2023
)Adds
CFConfigFile
reference if missing
Generated Files
Development Dockerfile
FROM ortussolutions/commandbox:latest
## Install curl and nano
RUN apt-get update && apt-get install -y curl nano
## Clean up the image
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
## Copy application files
COPY . /app
WORKDIR /app
## Install Dependencies
ENV BOX_INSTALL TRUE
## Expose port
EXPOSE 8080
## Set Healthcheck URI
ENV HEALTHCHECK_URI "http://127.0.0.1:8080/"
## Start the application
CMD ["box", "server", "start", "--console", "--force"]
Production Dockerfile
FROM ortussolutions/commandbox:latest
## Install required packages
RUN apt-get update && apt-get install -y curl nano && \
apt-get clean && rm -rf /var/lib/apt/lists/*
## Copy application files
COPY . /app
WORKDIR /app
## Install Dependencies
RUN box install --production
## Production optimizations
ENV ENVIRONMENT production
ENV BOX_SERVER_PROFILE production
## Security: Run as non-root user
RUN useradd -m -u 1001 appuser && \
chown -R appuser:appuser /app
USER appuser
## Expose port
EXPOSE 8080
## Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://127.0.0.1:8080/ || exit 1
## Start the application
CMD ["box", "server", "start", "--console"]
docker-compose.yml (Development with MySQL)
version: "3.8"
services:
app:
build: .
ports:
- "8080:8080"
environment:
ENVIRONMENT: development
DB_HOST: db
DB_PORT: 3306
DB_NAME: wheels
DB_USER: wheels
DB_PASSWORD: wheels
volumes:
- .:/app
- ../../../core/src/wheels:/app/vendor/wheels
- ../../../docs:/app/vendor/wheels/docs
- ../../../tests:/app/tests
command: sh -c "box install && box server start --console --force"
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: wheels
MYSQL_DATABASE: wheels
MYSQL_USER: wheels
MYSQL_PASSWORD: wheels
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
docker-compose.yml (Production with Nginx)
version: "3.8"
services:
app:
build: .
expose:
- 8080
environment:
ENVIRONMENT: production
DB_HOST: db
DB_PORT: 3306
DB_NAME: wheels
DB_USER: wheels
DB_PASSWORD: wheels
restart: always
depends_on:
- db
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
restart: always
depends_on:
- app
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: wheels
MYSQL_DATABASE: wheels
MYSQL_USER: wheels
MYSQL_PASSWORD: wheels
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
nginx.conf (Generated with --nginx)
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Performance
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
upstream app_backend {
server app:8080;
}
server {
listen 80;
server_name _;
# Max upload size
client_max_body_size 100M;
# Security headers (production only)
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
# Gzip compression (production only)
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json;
location / {
proxy_pass http://app_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Static assets caching
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
proxy_pass http://app_backend;
proxy_cache_valid 200 1d;
expires 1d;
add_header Cache-Control "public, immutable";
}
# Health check endpoint
location /health {
access_log off;
proxy_pass http://app_backend;
}
}
}
Database Configurations
MySQL
Image:
mysql:8.0
(default)Port: 3306
Credentials: wheels/wheels
Database: wheels
Root Password: wheels
PostgreSQL
Image:
postgres:15
(default)Port: 5432
Credentials: wheels/wheels
Database: wheels
MSSQL
Image:
mcr.microsoft.com/mssql/server:2019-latest
(default)Port: 1433
Credentials: sa/Wheels123!
Database: wheels
Note: Requires EULA acceptance
H2
Embedded: No separate container needed
Extension: Automatically added to Lucee deployments via Dockerfile
Connection: Configured in CFConfig.json
Storage: Within application container filesystem
Production vs Development Mode
Development Mode (default)
Source code mounted as volumes for hot-reload
Full development tools installed (curl, nano)
Debugging and verbose logging enabled
No restart policies
Direct port exposure (app accessible on configured port)
Development-friendly error messages
box install
runs on container start with--force
flagVolume mounts for Wheels core, docs, and tests (framework development)
Production Mode (--production
)
--production
)No source code volume mounts - code baked into image
Security hardened Dockerfile with non-root user (UID 1001)
Automatic restart policies (
restart: always
)Health checks configured (30s interval, 10s timeout, 60s start period, 3 retries)
Optimized image size with
box install --production
Production environment variable set
Additional .dockerignore exclusions (docs, IDE configs)
BOX_SERVER_PROFILE=production
environmentNo command override in docker-compose (uses CMD from Dockerfile)
Comparison Table
Source Volume Mount
✅ Yes
❌ No
Hot Reload
✅ Enabled
❌ Disabled
User
root
appuser (1001)
Restart Policy
none
always
Health Checks
❌ No
✅ Yes
Security Headers
❌ No
✅ Yes (with nginx)
Gzip Compression
❌ No
✅ Yes (with nginx)
Install Command
box install
box install --production
Image Size
Larger
Optimized
Nginx Reverse Proxy
When using --nginx
, an Nginx reverse proxy is configured between clients and your application.
Benefits
Load balancing ready: Upstream configuration supports multiple app instances
SSL termination point: Add SSL certificates to nginx without app changes
Static asset caching: 1-day cache for images, CSS, JS
Security headers: Production mode adds security headers
Gzip compression: Production mode compresses responses
WebSocket support: Upgrade headers configured
Request buffering: Better handling of slow clients
Health checks: Dedicated
/health
endpoint
Port Configuration
Development mode: Nginx listens on port 8080, app exposed internally
Production mode: Nginx listens on port 80, app exposed internally
App is only accessible through nginx when
--nginx
is used
Nginx Configuration Details
The generated nginx.conf
includes:
Upstream:
app_backend
pointing toapp:8080
(Docker service)Worker connections: 1024 concurrent connections
Client max body size: 100MB for file uploads
Proxy headers: Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto
WebSocket support: HTTP/1.1 with Upgrade and Connection headers
Timeouts: 60s for connect, send, and read operations
Static caching: 1 day expiration for assets
Health check:
/health
endpoint with no access logging
Production Security Headers (with --production --nginx)
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Referrer-Policy: no-referrer-when-downgrade
Production Gzip Compression (with --production --nginx)
Enabled for:
text/plain
text/css
text/xml
text/javascript
application/x-javascript
application/xml+rss
application/json
server.json Docker Configuration
The command automatically updates your server.json
with Docker-specific settings:
Before Docker Init
{
"name": "myapp",
"web": {
"host": "localhost",
"http": {
"port": "8080"
}
},
"openBrowser": true
}
After Docker Init
{
"name": "myapp",
"web": {
"host": "0.0.0.0",
"http": {
"port": "8080"
}
},
"openBrowser": false,
"CFConfigFile": "CFConfig.json",
"app": {
"cfengine": "lucee@6"
}
}
Why These Changes?
web.host
0.0.0.0
Docker containers must bind to all interfaces to accept external connections. Using localhost
or 127.0.0.1
prevents access from outside the container.
openBrowser
false
Docker containers run in headless mode with no GUI. Attempting to open a browser will fail and cause errors.
web.http.port
(from --port or existing)
Ensures the application port matches the Dockerfile EXPOSE and docker-compose port mapping.
CFConfigFile
CFConfig.json
Required for datasource configuration to work properly.
Port Priority
The port configuration follows this priority order:
--port
command argument (highest priority)Existing value in
server.json
Default:
8080
(lowest priority)
If you specify --port=9000
, the command will:
Update
server.json
with port9000
Configure Dockerfile to
EXPOSE 9000
Set docker-compose port mapping to
9000:9000
Environment Variables
The following environment variables are configured in docker-compose.yml:
ENVIRONMENT
Application environment mode
development
or production
BOX_SERVER_PROFILE
CommandBox server profile (production only)
production
DB_HOST
Database hostname (Docker service name)
db
DB_PORT
Database port
3306
, 5432
, 1433
DB_NAME
Database name
wheels
DB_USER
Database username
wheels
or sa
DB_PASSWORD
Database password
wheels
or Wheels123!
DB_TYPE
Database type (H2 only)
h2
Starting Your Docker Environment
After running wheels docker init
, start your containers:
# Start in detached mode
docker-compose up -d
# Start with build (after code changes in production)
docker-compose up -d --build
# View logs
docker-compose logs -f
# View specific service logs
docker-compose logs -f app
docker-compose logs -f nginx
# Stop containers
docker-compose down
# Stop and remove volumes (WARNING: deletes database data)
docker-compose down -v
# Restart a specific service
docker-compose restart app
# Rebuild and restart
docker-compose up -d --build --force-recreate
Notes
Requires Docker and Docker Compose installed
Use
--force
to skip confirmation prompts when overwriting existing filesserver.json is automatically configured for Docker compatibility:
web.host
changed to0.0.0.0
(required for Docker networking)openBrowser
set tofalse
(no GUI in containers)web.http.port
updated to match --port or existing valueCFConfigFile
added if missingCF engine version set (e.g.,
lucee@6
)
Custom
--port
overrides the port fromserver.json
Port priority:
--port
argument >server.json
> default (8080)Database passwords are set to defaults suitable for development only
Production deployments MUST use secrets management and secure passwords
Production mode creates security-hardened configurations with non-root users
Nginx adds reverse proxy capabilities for load balancing, caching, and security
H2 database runs embedded within the application container
Volume mounts in development assume Wheels framework development structure
When using
--nginx
, the app is only exposed internally to nginxCFConfig.json is updated with datasource configuration (skipped for H2)
Troubleshooting
Port conflicts
Problem: Port already in use on host machine
Solutions:
Update the port in
server.json
before runningwheels docker init
Use
--port
argument to specify a different portManually edit the ports in
docker-compose.yml
after generationStop the conflicting service:
lsof -ti:8080 | xargs kill
Database connection issues
Problem: Application cannot connect to database
Solutions:
Ensure the database container is fully started:
docker-compose logs db
Check for initialization errors in database logs
Verify CFConfig.json has correct datasource configuration
Confirm the
wheels-dev
datasource name matches your application configFor MSSQL, ensure password meets complexity requirements
Wait for database to fully initialize (can take 30-60 seconds first time)
Permission issues
Problem: Permission denied errors in production mode
Solutions:
The generated files have
777
permissions for development convenienceProduction Dockerfile runs as
appuser
(UID 1001)Ensure all files are readable by UID 1001
Check volume mount permissions on host
Adjust file permissions:
chmod -R 755 /path/to/app
Nginx not routing requests
Problem: 502 Bad Gateway or connection refused
Solutions:
Verify app service is running:
docker-compose ps
Check app service logs:
docker-compose logs app
Ensure app is listening on the correct port internally
Verify nginx config syntax:
docker-compose exec nginx nginx -t
Check nginx logs:
docker-compose logs nginx
Restart services:
docker-compose restart app nginx
Force overwrite not working
Problem: Still getting prompted despite using --force
Solutions:
Ensure correct syntax:
wheels docker init --force
(not--force=true
)Check for boolean parameter issues in command
Use the exact parameter name:
--force
H2 database not working
Problem: H2 extension not loading or database errors
Solutions:
Verify H2 extension was added to Dockerfile
Check Lucee admin for H2 extension installation
Ensure CFConfig.json doesn't have conflicting datasource config
Check application logs for H2 initialization errors
H2 works with Lucee only (not Adobe ColdFusion)
Container not accessible from host
Problem: Cannot access the application at http://localhost:8080
Solutions:
Verify
server.json
hasweb.host
set to0.0.0.0
(notlocalhost
or127.0.0.1
)Check if port is already in use:
lsof -ti:8080
(Unix) ornetstat -ano | findstr :8080
(Windows)Ensure docker-compose port mapping matches server.json port
Check container logs:
docker-compose logs app
Restart containers:
docker-compose restart app
If manually edited, run
wheels docker init --force
to regenerate proper configuration
Application attempts to open browser
Problem: Errors about browser opening or display issues
Solutions:
Verify
server.json
hasopenBrowser: false
Run
wheels docker init --force
to update server.json automaticallyManually set
"openBrowser": false
in server.jsonRebuild containers:
docker-compose up -d --build
See Also
wheels docker deploy - Deploy using Docker
wheels deploy - General deployment commands
CommandBox Docker Images - Official CommandBox images
Docker Compose Documentation - Docker Compose reference
Nginx Documentation - Nginx configuration reference
Last updated
Was this helpful?