Migration - Upgrades

How to Migrate ColdFusion Sessions During Server Switch

Contents show

Introduction

Migrating application sessions while switching ColdFusion servers is one of those tasks that seems simple until it isn’t. Sessions hold who a user is, what they’ve added to the cart, and what access they have. Dropping them leads to forced re-Authentication, lost work, and revenue impacts. A careful plan lets you upgrade Infrastructure (new ColdFusion version, OS, JVM, or hosting) and still preserve session continuity, support High availability, and enable rolling or blue‑green deployments without user-visible disruption.

To achieve this, you’ll combine one or more strategies: session stickiness at the load balancer, shared session storage (Redis/Memcached), Tomcat-based Session replication, or a controlled session drain. This guide details how to choose and implement the right pattern for Adobe ColdFusion (and notes for Lucee), with practical steps, Configuration examples, and validation checklists.


Prerequisites / Before You Start

  • Inventory and documentation

    • List current ColdFusion version (e.g., CF11, 2016, 2018, 2021, 2023) and target version.
    • Note whether you use classic CFID/CFTOKEN sessions or J2EE sessions (JSESSIONID).
    • Identify frameworks (ColdBox, FW/1, Fusebox), SSO/IdP Integration (SAML/OIDC), and any session-dependent middleware.
    • Confirm application sets this.sessionManagement in Application.cfc.
  • Backups and rollback

    • Full backup of code, ColdFusion Administrator Configuration (cfusion/lib/neo*.xml files), web Server configuration (IIS/Apache/Nginx), and any database used for client variables.
    • Snapshot VM/instance images where possible; export existing load balancer configuration.
    • A clear rollback plan that can restore traffic to the old server within minutes.
  • Environment readiness

    • New server(s) built with the target ColdFusion/JDK versions, patches, connectors (IIS/Apache), and identical hotfix levels across nodes.
    • Time synchronization (NTP) across all nodes to avoid session expiry skew.
    • Matching JVM heap settings and encoding/timezone settings if session data depends on them.
  • Networking and Security

    • TLS configured end-to-end; plan cookie attributes: Secure, HttpOnly, SameSite (often SameSite=None for SSO/cross-site).
    • Decide cookie domain and path; ensure they match on old and new servers.
    • Confirm firewall rules for cluster replication or Redis/Memcached if used.
  • Dependencies and libraries

    • If using external session stores, have Redis or Memcached deployed and reachable, with failover and persistence policies.
    • If using Tomcat clustering, ensure ColdFusion’s embedded Tomcat can open required ports; provide a cluster membership strategy (static or via DNS).
    • Confirm that session contents are serializable if using J2EE sessions with replication; avoid storing complex Java objects or file handles in session scope.
  • Testing plan

    • A representative test user journey script (login, cart, form entries).
    • Load test or synthetic transactions to validate under realistic traffic.
    • A canary Deployment approach (direct a small percentage of users first).

Choosing a Session Migration strategy

Strategy A: Sticky Sessions + Controlled Drain (simplest, least risky)

  • Keep sessions local to each node and enable persistent stickiness on the load balancer based on JSESSIONID.
  • Drain the old server: stop sending new sessions there, but let existing sessions live until timeout.
  • Pros: Easiest, minimal code/config changes.
  • Cons: Requires time equal to max session timeout; not true session failover.
See also  How to Test Performance Before and After Migration

Strategy B: Shared Session Store (Redis/Memcached)

  • Externalize session state so any server can serve any request.
  • Pros: Real failover; enables blue-green and auto-Scaling; works across versions if data is compatible.
  • Cons: Requires additional Infrastructure; must ensure serialization compatibility and Performance.

Strategy C: Tomcat Cluster Session replication

  • Use Tomcat’s DeltaManager/BackupManager to replicate J2EE session state between nodes.
  • Pros: No separate store; session failover.
  • Cons: Configuration complexity; network chattiness; all session data must be serializable.

Below is a quick Comparison:

Approach Zero-downtime cutover Complexity Infra add-on Best for
Sticky + Drain Near-zero (after warm-up) Low None Gradual cutovers, simple fleets
Shared Store (Redis) Yes Medium Redis Containers/auto-Scaling, multi-AZ
Tomcat Replication Yes Medium-High None Small clusters, stateful HA

Step-by-Step Migration guide

1) Decide on Session Type and Cookie Policy

If you currently rely on CFID/CFTOKEN, consider switching to J2EE sessions (JSESSIONID). This aligns with load balancers, Tomcat clustering, and external session managers.

In Application.cfc:

cfml
component {

this.name = “MyApp”;
this.sessionManagement = true;
this.sessionTimeout = createTimeSpan(0, 0, 45, 0); // 45 minutes
this.setClientCookies = true;
this.loginStorage = “session”;

// Use J2EE sessions to support LB stickiness and replication
this.sessionType = “J2EE”; // Adobe CF 2016+; for older versions, enable in CF Admin

// Cookie hardening
this.sessionCookie = {
httpOnly = true,
secure = true,
sameSite = “None”, // set to Lax/Strict if no cross-site flows
path = “/”,
domain = “example.com” // ensure consistency across old/new servers
};
}

Also enable “Use J2EE Session variables” in ColdFusion Administrator if not controlling via Application.cfc.

Harden login tokens similarly and ensure consistent cookie domain/path across environments.

2) Prepare the New Server(s)

  • Install ColdFusion with the same or target version, apply latest updates/hotfixes.
  • Align JVM and regional settings (timezone, locale) to avoid time-based mismatches.
  • Verify CF web connector on IIS/Apache/Nginx and AJP if used. Consider moving off AJP if not needed for Security reasons; use HTTP/HTTPS connectors.

3) Choose and Implement the Migration Pattern

3.1 Pattern A: Sticky Sessions + Drain

  • Enable stickiness in your load balancer based on JSESSIONID.

NGINX example (using a hash of JSESSIONID):

nginx
upstream app {
hash $cookie_JSESSIONID consistent;
server old-server:443;
server new-server:443;
}

server {
listen 443 ssl;
location / {
proxy_pass https://app;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $remote_addr;
}
}

HAProxy example:

haproxy
backend app
balance hdr(JSESSIONID)
cookie JSESSIONID prefix nocache
server old old-server:443 ssl verify none cookie S1
server new new-server:443 ssl verify none cookie S2

  • Start with both old and new servers in rotation. Once new is warmed up, set old to “drain”:
    • In NGINX/HAProxy/ALB, stop routing new sessions to the old node (weight=0), but allow existing sticky sessions to continue.
  • Optionally reduce sessionTimeout a few hours beforehand to accelerate drain.
  • After session count on old server approaches zero, remove it.

Tip: Build a session registry to observe active sessions (for visibility only):

cfml
component {

this.name = “MyApp”;
this.sessionManagement = true;

function onSessionStart() {
application.sessions = application.sessions ?: {};
application.sessions[session.sessionid] = now();
}

function onSessionEnd(struct sessionScope, struct appScope) {
if (structKeyExists(appScope, “sessions”)) {
structDelete(appScope.sessions, sessionScope.sessionid, true);
}
}
}

Note: session.sessionid exists with J2EE sessions; if not, use cookie value.

3.2 Pattern B: Shared Session Store (Redis)

  • Use a Tomcat session manager that stores J2EE sessions in Redis. One popular approach is Redisson for Tomcat.

In TOMCAT_HOME/conf/context.xml (or the ColdFusion instance conf), add:

xml




Example redisson.yaml:

yaml
singleServerConfig:
address: “redis://redis:6379”
database: 0
password: “strongpassword”
threads: 16
nettyThreads: 32
codec: !<org.redisson.codec.SerializationCodec> {}

Considerations:

  • All objects stored in session must be Java-serializable. In CF, prefer simple data: strings, numbers, arrays, structs, queries.
  • Avoid storing CFC instances, file handles, large binary blobs; store identifiers instead.
  • Validate Performance: Redis latency, connection pooling, TTL alignment with sessionTimeout.

3.3 Pattern C: Tomcat Cluster Replication

Enable clustering in server.xml:

xml










Recommendations:

  • Use static membership or unicast in cloud environments where multicast is blocked.
  • Ensure identical jvmRoute per node (and configure load balancer to respect it) if using route-based stickiness.
  • Test failover by stopping one node and observing session persistence on another.
See also  How to Migrate ColdFusion Datasources to a New Database Server

4) Make Session Data Serializable and Minimal

  • Keep session scope lean: userId, roles, locale, feature flags, cart IDs. Move bulky data to database or cache keyed by session ID.
  • Replace CFCs in session with references (e.g., IDs) and rehydrate per request from cache/DB.
  • Run serialization tests in staging:
    • Add a page that serializes session scope via Java output stream and catches exceptions.
    • Exercise user flows to ensure no NotSerializableException occurs.

5) Configure Cookie Consistency and Security

  • Ensure the cookie used for stickiness (JSESSIONID) is the same across nodes:
    • Same domain, path, Secure/HttpOnly flags identical.
    • SameSite considerations:
      • For SSO redirect flows or cross-site embeds, set SameSite=None; Secure=true.
      • Otherwise prefer SameSite=Lax for additional CSRF protection.
  • Confirm SSL termination behavior at the load balancer; if SSL terminates there and re-encrypts to the app, preserve Secure cookies.

6) Execute a Blue-Green or Rolling Cutover

  • Blue-Green:

    • Bring up the “green” environment fully.
    • Mirror traffic with read-only synthetic checks and run smoke tests.
    • Shift a small percentage of real users (weighted routing). Monitor errors, latency, and session continuity.
    • Gradually increase to 100%, then decommission “blue” after drain completes.
  • Rolling:

    • Add one new node behind LB, validate.
    • Drain one old node, remove it, repeat until all are upgraded.

7) Monitor and Tune

  • Metrics to watch:
    • Login success rates, 401/403 spikes, cart loss reports.
    • Session counts per node, session creation rate, average session lifetime.
    • Redis/Tomcat replication latency and network errors.
  • Logging:
    • Add correlation IDs and log session ID hashes (never full tokens) to trace cross-node requests.
    • Alert on sudden drops in concurrent sessions.

8) Plan and Test Rollback

  • Keep old environment warm until you pass stability criteria.
  • Maintain data compatibility (DB schema, caches) to enable quick failback.
  • Have a one-command LB switch or infrastructure-as-code plan ready.

Risks, Common Issues, and How to Avoid Them

  • Session loss at cutover

    • Cause: switching cookie names (CFID/CFTOKEN to JSESSIONID) without coexistence.
    • Fix: run both in parallel temporarily or keep sessionType stable during cutover; use sticky drain.
  • Serialization failures

    • Cause: storing non-serializable objects in session when using Redis/replication.
    • Fix: Audit session content; keep primitives, arrays, structs, queries only.
  • Cookie domain/path mismatches

    • Symptoms: new server sets a different cookie inaccessible to old path/domain.
    • Fix: set this.sessionCookie.domain/path consistently; match LB rewrites.
  • SameSite/HTTPS breakage with SSO

    • Symptoms: users loop at login or lose session after IdP redirect.
    • Fix: SameSite=None and Secure=true; terminate TLS correctly end-to-end.
  • Clock skew

    • Symptoms: immediate session expiration on one node.
    • Fix: ensure NTP sync; align sessionTimeout and TTL settings in Redis/cluster.
  • Load balancer misconfiguration

    • Symptoms: bouncing between nodes despite stickiness, especially after 302 redirects.
    • Fix: sticky based on JSESSIONID cookie; preserve cookies on redirects; avoid IP-hash only.
  • Version incompatibility

    • Symptoms: session deserialization errors when mixing CF versions or JVMs.
    • Fix: avoid cross-version deserialization unless tested; prefer drain or shared store that serializes consistently.
  • Excessive session size

    • Symptoms: high latency, CPU spikes, network overhead in replication.
    • Fix: cap session size; move large objects to cache/db; compress only if needed and measured.

Post-Migration Checklist

  • Functional

    • Users remain logged in after cutover.
    • Shopping carts, wizards, and multi-step forms retain state.
    • File uploads and CSRF tokens still function.
  • Technical

    • JSESSIONID cookie attributes (Secure, HttpOnly, SameSite, domain, path) are correct.
    • Sticky routing or shared session works across all nodes.
    • No serialization exceptions in logs.
    • Session counts stable; memory utilization within targets; GC healthy.
  • Security

    • SSL everywhere as intended; HSTS if required.
    • Admin endpoints not accessible externally.
    • No leakage of session IDs in URLs or logs.
  • Observability

    • Dashboards show error rates, p95 latency, session churn.
    • Alerts configured for spikes in 401/403/500, Redis unavailability, or cluster failures.
  • Documentation

    • Architecture diagram updated (LB, sessions, cache).
    • Runbooks for scale-out and node replacement include session steps.
See also  How to Handle Deprecated Tags During ColdFusion Upgrade

Configuration Examples

Application.cfc essentials

cfml
component {
this.name = “MyApp”;
this.sessionManagement = true;
this.sessionType = “J2EE”;
this.sessionTimeout = createTimeSpan(0, 1, 0, 0);
this.setClientCookies = true;
this.sessionCookie = {
httpOnly = true,
secure = true,
sameSite = “None”,
domain = “example.com”,
path = “/”
};

function onApplicationStart() { return true; }
function onSessionStart() { / initialize session state / }
}

web.xml session-config (optional server-level)

xml


60

true
true
JSESSIONID
COOKIE

AWS ALB stickiness

  • Use “stickiness by application cookie” set to JSESSIONID.
  • Stickiness duration equal to or slightly larger than sessionTimeout.

Special Considerations

Migrating from CFID/CFTOKEN to JSESSIONID

  • Keep CFID/CFTOKEN for one release while introducing JSESSIONID for stickiness.
  • Add logic to treat an existing CFID/CFTOKEN session as authoritative; gradually transition to JSESSIONID by re-authenticating users once, or map values on first request to establish J2EE session.

Lucee/Railo notes

  • Lucee supports J2EE sessions and can integrate with Redis via extensions.
  • Configuration differs slightly (lucee-server.xml, context.xml). The principles remain: serializable session scope, consistent cookies, and a chosen failover strategy.

Containers/Kubernetes

  • Avoid local in-memory sessions without stickiness.
  • Favor Redis-backed sessions or Tomcat replication for rolling updates and scaling.
  • Use readiness/liveness probes that do not create new sessions to avoid noise.

Validation Steps

  • Pre-Cutover

    • Run smoke tests on new nodes directly (hosts file or dedicated URL) to confirm session behavior.
    • Verify new node sets the same cookie parameters as old.
  • Canary

    • Route 5–10% of traffic; monitor auth success rate, error rates.
    • Check cross-node Navigation by deliberately bouncing a user across nodes (disable stickiness temporarily in a test environment) if using shared store or replication.
  • Failover test

    • Terminate one node and ensure users continue seamlessly.
    • Verify logins and cart contents persist.
  • Performance

    • Measure p95/p99 latencies before/after; ensure no regression from session store latency or replication overhead.
  • Security

    • Validate that session cookies are not exposed over HTTP.
    • Verify SameSite behavior against SSO flows.

Practical Examples of Load Balancer Config

NGINX (round-robin + sticky by cookie)

nginx
upstream cf_pool {
hash $cookie_JSESSIONID consistent;
server cf-node-1:8443;
server cf-node-2:8443;
}

server {
listen 443 ssl;
location / {
proxy_pass https://cf_pool;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $host;
}
}

HAProxy (cookie stickiness)

haproxy
backend cf_app
balance roundrobin
cookie JSESSIONID prefix nocache indirect
server s1 10.0.1.10:8443 ssl verify none cookie s1 check
server s2 10.0.1.11:8443 ssl verify none cookie s2 check


Maintenance Tips

  • Periodically Audit session size; log the estimated size for trending.
  • Review SameSite policies whenever you change SSO or embed flows.
  • For Redis: enable monitoring for memory fragmentation, evictions, and replication lag.
  • For replication: limit session churn by avoiding frequent writes to session scope; update only when necessary.

FAQ

Can I migrate sessions without any user interruptions?

Yes. Use either sticky sessions with a controlled drain or a shared session store (Redis) or Tomcat replication. Validate in staging, then perform a blue-green or rolling cutover while monitoring. Users should keep their sessions if cookie attributes and serialization are consistent.

Do I have to move from CFID/CFTOKEN to JSESSIONID?

No, but it simplifies load balancer stickiness and enables Tomcat-based replication and external managers. If you stay on CFID/CFTOKEN, prefer the sticky+drain approach. For long-term flexibility and Standards alignment, migrating to JSESSIONID is recommended.

What if I’m using Lucee instead of Adobe ColdFusion?

The principles are identical: enable J2EE sessions, ensure serializable session data, and pick a strategy (stickiness, Redis, replication). Lucee has extensions for Redis session storage. Configuration locations differ, but the Session migration patterns remain the same.

How can I reduce risk before cutover?

Run canary traffic first, shorten sessionTimeout ahead of time to accelerate drains, audit session contents for serialization safety, align cookie attributes across environments, and have a documented rollback route in your load balancer or DNS.

Is Redis better than Tomcat replication?

It depends. Redis excels for larger clusters, auto-scaling, and cross-AZ resilience, at the cost of extra infrastructure. Tomcat replication is simpler to deploy in small, stable clusters but adds network overhead and requires careful tuning. Choose based on scale, reliability needs, and operational maturity.

About the author

Aaron Longnion

Aaron Longnion

Hey there! I'm Aaron Longnion — an Internet technologist, web software engineer, and ColdFusion expert with more than 24 years of experience. Over the years, I've had the privilege of working with some of the most exciting and fast-growing companies out there, including lynda.com, HomeAway, landsofamerica.com (CoStar Group), and Adobe.com.

I'm a full-stack developer at heart, but what really drives me is designing and building internet architectures that are highly scalable, cost-effective, and fault-tolerant — solutions built to handle rapid growth and stay ahead of the curve.