Skip to main content

CMS & E-commerce Deployment Guide

CloudForge 3.1.0 introduces first-class support for PHP-based content management systems, e-commerce platforms, forums, wikis, LMS, and social networking applications — 19 built-in platforms plus a public plugin example (cloudforge-sample) — all deployable with a single topology type: cms-service.

Local development: 7 of the 19 built-in platforms have Docker containers in docker-compose.yml and have been verified running locally. Since Fargate is also a Docker runtime, local verification directly validates the container behavior for AWS deployments — CloudForge handles all environment-specific wiring (RDS endpoint, ElastiCache, EFS) via the ApplicationSpec.


Quick Start

{
"cfc": {
"topology": "cms-service",
"applicationId": "wordpress",
"runtime": "fargate",
"env": "prod",
"domain": "example.com",
"subdomain": "blog",
"enableSsl": true,
"authMode": "alb-oidc"
}
}

That single config block provisions:

  • ECS Fargate container running the official WordPress PHP-FPM image
  • ALB with HTTPS listener and health checks
  • RDS MySQL (from DatabaseSpec requirements)
  • S3 media bucket (WordPress supportsS3MediaStorage() = true)
  • ElastiCache Redis (WordPress supportsObjectCache() = true)
  • CloudFront CDN with separate behaviors for media, static assets, and the wp-admin bypass
  • Route53 A + AAAA alias records
  • All correct Redis/DB env vars injected into the container automatically

Available Platforms

CMS — Content Management

ApplicationIDPHPOIDCS3 MediaRedisMultisiteLocal DockerSource
WordPresswordpress8.2✅ :8087built-in
Drupaldrupal8.2✅ :8090built-in
Joomlajoomla8.2✅ :8091built-in
TYPO3typo38.2built-in
Concrete CMSconcrete-cms8.2built-in
October CMSoctober-cms8.2built-in
Craft CMScraft-cms8.2✅ (ALB)cloudforge-sample

E-commerce

ApplicationIDPHPOIDCS3 MediaRedisLocal DockerNotes
WooCommercewoocommerce8.2✅ :8089Extends WordPress
Magento 2magento8.2✅ :80933 Redis DBs; requires OpenSearch
PrestaShopprestashop8.1
OpenCartopencart8.2✅ :8094
Syliussylius8.2
Bagistobagisto8.2

Forum / Community

ApplicationIDPHPLocal DockerNotes
phpBBphpbb8.2Classic bulletin board
Flarumflarum8.2Modern discussion platform
MyBBmybb8.2Free bulletin board

CRM

ApplicationIDPHPLocal DockerNotes
SuiteCRMsuitecrm8.2Open-source CRM

Wiki

ApplicationIDPHPLocal DockerNotes
MediaWikimediawiki8.2Powers Wikipedia

LMS — Learning Management

ApplicationIDPHPLocal DockerNotes
Moodlemoodle8.2Most popular open-source LMS

Social Networking

ApplicationIDPHPOIDCLocal DockerNotes
UNA (Dolphin)dolphin-una8.2✅ (ALB)✅ :8092Social platform framework

How It Works

The cms-service Topology

CmsServiceTopologyConfiguration reads each platform's declared capabilities via the CmsSpec interface and conditionally provisions infrastructure — no hardcoded platform names anywhere in the wiring:

CmsSpec.supportsS3MediaStorage() → creates S3 media bucket
CmsSpec.supportsCdnIntegration() → creates CloudFront distribution (deferred until ALB is ready)
CmsSpec.supportsObjectCache() → creates ElastiCache Redis cluster
CmsSpec.hasScheduledTasks() → registers system cron commands

Environment Variables

Each CMS declares its own connection variable names via redisEnvVars() and databaseEnvVars() on the spec. There are no switch statements on application IDs — a new plugin just overrides the default methods.

WordPress example:

REDIS_HOST=… WP_REDIS_HOST=… WP_REDIS_PORT=6379 WP_REDIS_DATABASE=0
DB_HOST=… WORDPRESS_DB_HOST=…:3306 WORDPRESS_DB_NAME=wordpress

Magento example (Redis uses 3 databases):

MAGENTO_CACHE_BACKEND_REDIS_DATABASE=0
MAGENTO_PAGE_CACHE_BACKEND_REDIS_DATABASE=1
MAGENTO_SESSION_BACKEND_REDIS_DATABASE=2

CDN Path Routing

Each CMS declares three path groups; CmsCdnConfiguration maps them to CloudFront behaviors automatically:

MethodBehaviorCache
cdnMediaPaths()S3 origin7-day TTL
cdnStaticPaths()ALB origin1-day TTL
cdnAdminPaths()ALB origin, all headers forwardedDisabled

Platform-Specific Notes

WordPress / WooCommerce

Resources required: MySQL 8.0, Redis 7, S3 bucket, CloudFront
System cron: WordPress WP-Cron disabled; system cron fires every 15 min via curl
CLI tool: WP-CLI installed automatically on EC2
OIDC method: OpenID Connect Generic plugin
Multisite: Supported (subdirectory mode by default)

{
"cfc": {
"topology": "cms-service",
"applicationId": "wordpress",
"runtime": "fargate",
"domain": "myblog.com",
"enableSsl": true,
"authMode": "alb-oidc"
}
}

Magento 2

Resources required: MySQL 8.0, Redis 7 (3 databases), S3 bucket, CloudFront
Instance type: t3.xlarge default (4 vCPU / 8 GB); production requires m5.xlarge+
OIDC method: miniOrange OIDC module
Cron groups: default, index, consumers, ddg_automation — all registered as system cron

{
"cfc": {
"topology": "cms-service",
"applicationId": "magento",
"runtime": "fargate",
"cpu": 4096,
"memory": 8192,
"securityProfile": "production",
"complianceFrameworks": "PCI-DSS,SOC2"
}
}

⚠️ PCI-DSS note: WooCommerce and Magento process or touch payment data. Enable complianceFrameworks: "PCI-DSS" and review the PCI-DSS Compliance Guide.

Drupal

Resources required: MySQL 8.0 or PostgreSQL 14, Redis 7, S3 bucket (via s3fs module)
OIDC method: Native OpenID Connect module
CLI tool: Drush installed automatically on EC2

Joomla

Resources required: MySQL 8.0, Redis 7
OIDC method: miniOrange OAuth plugin
Admin bypass path: /administrator/* routes through CloudFront with caching disabled

Craft CMS (cloudforge-sample plugin)

Source: CraftCmsApplicationSpec — demonstrates the CmsSpec + DatabaseSpec plugin pattern for external plugin authors.

Resources required: MySQL 8.0 or PostgreSQL 14, Redis 7 (native since Craft 4), S3 (craftcms/aws-s3), CloudFront
OIDC method: verbb/auth plugin (ALB-OIDC mode; application-level OIDC via verbb/auth is optional)
CLI tool: php craft
Queue runner: System cron every minute — php craft queue/run (preferred over Craft's internal runner for production)

Critical: Craft's public web root is the web/ subdirectory (/var/www/html/web), not the application root (/var/www/html). Nginx must point at the subdirectory or requests will fail. The documentRoot() and containerDataPath() methods return different values precisely for this reason.

Protected paths: /admin/* only — Craft's public front-end is unauthenticated by design.

{
"cfc": {
"topology": "cms-service",
"applicationId": "craft-cms",
"runtime": "fargate",
"domain": "example.com",
"subdomain": "site",
"enableSsl": true,
"authMode": "alb-oidc"
}
}

Environment variables injected automatically:

VariableDescription
CRAFT_DB_DRIVERmysql or pgsql
CRAFT_DB_SERVERRDS endpoint
CRAFT_DB_PORT / CRAFT_DB_DATABASE / CRAFT_DB_USERDatabase connection
CRAFT_REDIS_HOSTNAME / CRAFT_REDIS_PORT / CRAFT_REDIS_DATABASERedis cache
CRAFT_ENVIRONMENTproduction (SSL) or staging
CRAFT_SECURITY_KEYInjected from Secrets Manager at deploy time
PRIMARY_SITE_URLFull HTTPS/HTTP URL including protocol

Resource Sizing by Platform

CategoryDefault CPUDefault MemoryEC2 Instance
Simple CMS (WordPress, Joomla)1024 (1 vCPU)2048 MBt3.small
E-commerce (WooCommerce, PrestaShop)2048 (2 vCPU)4096 MBt3.medium
Enterprise (Magento)4096 (4 vCPU)8192 MBt3.xlarge
Forum / Wiki / LMS1024 (1 vCPU)2048 MBt3.small

Defaults are declared on the @CmsPlugin annotation and can be overridden in cdk.json:

{
"cfc": {
"cpu": 2048,
"memory": 4096
}
}

Writing a Custom CMS Plugin

The Craft CMS plugin in cloudforge-sample is a complete, production-quality reference implementation. It demonstrates: non-root document root, queue-based cron, Craft-native env var naming, and ALB-OIDC path protection.

If you have a PHP application not listed above, create a plugin in minutes:

@CmsPlugin(
value = "my-cms",
category = "cms",
displayName = "My CMS",
description = "A custom CMS platform",
phpVersion = "8.2",
defaultCpu = 1024,
defaultMemory = 2048,
supportsOidc = true,
requiresDatabase = true,
supportsS3Media = true,
supportsObjectCache = true,
defaultImage = "my-org/my-cms:latest"
)
public class MyCmsApplicationSpec implements CmsSpec, DatabaseSpec {

@Override public String applicationId() { return "my-cms"; }
@Override public String defaultContainerImage() { return "my-org/my-cms:latest"; }
@Override public int applicationPort() { return 80; }
@Override public String containerDataPath() { return "/var/www/html"; }
@Override public String efsDataPath() { return "/my-cms"; }
@Override public String volumeName() { return "myCmsData"; }
@Override public String containerUser() { return "33:33"; }
@Override public String efsPermissions() { return "755"; }
@Override public String mediaUploadPath() { return "/var/www/html/uploads"; }
@Override public String phpVersion() { return "8.2"; }
@Override public List<String> requiredPhpExtensions() {
return List.of("mysqli", "pdo_mysql", "gd", "curl", "mbstring", "zip");
}

// CDN path routing — declare what goes where
@Override public List<String> cdnMediaPaths() { return List.of("/uploads/*"); }
@Override public List<String> cdnStaticPaths() { return List.of("/assets/*", "/themes/*"); }
@Override public List<String> cdnAdminPaths() { return List.of("/admin/*"); }

// CMS-specific Redis env vars (merged with generic REDIS_HOST/REDIS_PORT)
@Override
public Map<String, String> redisEnvVars(String host, int port) {
Map<String, String> env = new HashMap<>();
env.put("REDIS_HOST", host);
env.put("REDIS_PORT", String.valueOf(port));
env.put("MY_CMS_REDIS_HOST", host);
env.put("MY_CMS_REDIS_PORT", String.valueOf(port));
return env;
}

// CMS-specific DB env vars
@Override
public Map<String, String> databaseEnvVars(String host, int port, String name, String user) {
Map<String, String> env = new HashMap<>();
env.put("DB_HOST", host); env.put("DB_PORT", String.valueOf(port));
env.put("DB_NAME", name); env.put("DB_USER", user);
env.put("MY_CMS_DB_HOST", host);
env.put("MY_CMS_DB_NAME", name);
return env;
}

@Override
public DatabaseRequirement databaseRequirement() {
return DatabaseRequirement.required("mysql", "8.0")
.withInstanceClass("db.t3.micro")
.withStorage(20)
.withDatabaseName("my_cms");
}
}

Then register in META-INF/services/com.cloudforge.core.interfaces.ApplicationSpec:

com.example.MyCmsApplicationSpec

Deploy with:

{ "cfc": { "topology": "cms-service", "applicationId": "my-cms" } }

Discovery API

CmsLoader provides programmatic access to all registered CMS plugins:

// All platforms
Map<String, CmsSpec> all = CmsLoader.discover();

// By category
List<CmsSpec> ecommerce = CmsLoader.discoverEcommerce();
List<CmsSpec> forums = CmsLoader.discoverForums();

// Feature-filtered
List<CmsSpec> oidcReady = CmsLoader.discoverOidcEnabled();
List<CmsSpec> s3Ready = CmsLoader.discoverS3MediaSupported();

// Lookup by ID
Optional<CmsSpec> wp = CmsLoader.findById("wordpress");

// Print catalog
System.out.println(CmsLoader.printCatalog());

Compliance Considerations

Platform CategoryFrameworksNotes
E-commerce (Magento, WooCommerce)PCI-DSS required, SOC2Store/process payment data
LMS (Moodle)FERPA, GDPRStudent records
CRM (SuiteCRM)GDPR, SOC2Customer PII
CMS (WordPress, Drupal)SOC2, GDPRUser content and PII
Forum / SocialGDPR, (FERPA if educational)User posts, PII

Enable compliance frameworks in cdk.json:

{
"cfc": {
"complianceFrameworks": "PCI-DSS,SOC2",
"complianceMode": "enforce",
"securityProfile": "production"
}
}

Local Development

Seven platforms have verified Docker containers in docker-compose.yml. Start them with:

./scripts/docker-start.sh infrastructure cms
ContainerPortStatus
WordPresshttp://localhost:8087✅ Verified
WooCommercehttp://localhost:8089✅ Verified
Drupalhttp://localhost:8090✅ Verified
Joomlahttp://localhost:8091✅ Verified
UNA (Dolphin)http://localhost:8092✅ Verified
Magento 2http://localhost:8093✅ Verified
OpenCarthttp://localhost:8094✅ Verified

Local containers connect to shared MySQL (port 3306), PostgreSQL (port 5432), and Redis (port 6379) also in docker-compose.yml. These mirror the RDS/ElastiCache resources CloudForge provisions on AWS.

Craft CMS (craft-cms) deploys to AWS via the cloudforge-sample plugin but has no local Docker container — test it by deploying to a dev Fargate environment.



CloudForge 3.1.0 — CMS/E-commerce Platform Support