Deploy Classic UI Example¶
This guide shows you how to deploy the Classic UI example to your Kubernetes cluster.
What You’ll Deploy¶
The Classic UI example provides traditional Plone with server-side rendering:
Plone 6.1 Classic UI (traditional interface, no separate frontend)
PostgreSQL with RelStorage (CloudNativePG or Bitnami)
Varnish HTTP caching with kube-httpcache
Ingress with TLS (Traefik or Kong)
Simpler architecture (single backend service)
Classic UI vs Volto¶
Feature |
Classic UI |
Volto |
|---|---|---|
Architecture |
Single backend |
Frontend + Backend |
Rendering |
Server-side |
Client-side (React) |
Deployment |
Simpler |
More complex |
Best for |
Migrations, intranets |
Modern projects |
Tip
Choose Classic UI if you’re migrating from older Plone versions or need specific Classic UI add-ons. For new projects, consider Volto.
Prerequisites¶
Same as the Production Volto guide, you need:
Ingress controller (Traefik or Kong)
cert-manager
kube-httpcache operator
PostgreSQL operator (CloudNativePG or Bitnami)
See Setup Prerequisites for detailed instructions.
Step 1: Get the Example¶
git clone https://github.com/bluedynamics/cdk8s-plone.git
cd cdk8s-plone/examples/classic-ui
Step 2: Install Dependencies¶
npm install
Step 3: Import CRDs¶
npm run import
Step 4: Configure Environment¶
Create .env from the example:
cp .env.example .env
Edit .env:
# Your domains
DOMAIN_CACHED=plone.example.com
DOMAIN_UNCACHED=plone-test.example.com
DOMAIN_MAINTENANCE=plone-admin.example.com
# Your cert-manager ClusterIssuer
CLUSTER_ISSUER=letsencrypt-prod
# Optional: Custom backend image
#PLONE_BACKEND_IMAGE=plone/plone-backend:6.1.3
# Database: 'bitnami' or 'cloudnativepg'
DATABASE=cloudnativepg
Note
Classic UI only needs one image (backend). There’s no frontend image configuration.
Step 5: Generate Manifests¶
npm run synth
Creates dist/plone-classic.k8s.yaml (~27 KB, smaller than Volto’s 32 KB).
Step 6: Review Manifests¶
# Count resources
grep "^kind:" dist/plone-classic.k8s.yaml | sort | uniq -c
# Dry run
kubectl apply --dry-run=client -f dist/plone-classic.k8s.yaml
Step 7: Deploy¶
kubectl apply -f dist/plone-classic.k8s.yaml
Or to a specific namespace:
kubectl apply -f dist/plone-classic.k8s.yaml -n plone
Step 8: Monitor Deployment¶
# Watch pods
kubectl get pods -l app.kubernetes.io/part-of=plone -w
# Wait for ready
kubectl wait --for=condition=ready pod \
-l app.kubernetes.io/part-of=plone \
--timeout=300s
Note
Classic UI deploys fewer pods than Volto (no frontend pods).
Step 9: Verify Services¶
kubectl get svc -l app.kubernetes.io/part-of=plone
You should see:
plone-backend(Classic UI service)plone-httpcache(Varnish cache)Database service
Step 10: Check Ingress¶
kubectl get ingress
kubectl get certificate
Step 11: Access Your Site¶
Once DNS and TLS are ready:
Public (cached): https://plone.example.com
Testing (uncached): https://plone-test.example.com
Maintenance: https://plone-admin.example.com
Create Plone Site¶
Access maintenance domain: https://plone-admin.example.com
Click “Create a new Plone site”
Configure:
Site ID:
PloneTitle: Your site name
Language: Select language
Add-ons: Choose Classic UI add-ons
Click “Create Plone Site”
Key Differences from Volto¶
Architecture¶
Classic UI routing is simpler - all traffic goes to the backend:
Traffic → Ingress → Varnish → Plone Backend (Classic UI)
Compared to Volto:
Traffic → Ingress → {Varnish → Frontend, Backend}
Ingress Routes¶
Classic UI uses virtual host rewriting for direct backend access:
Cached: Routes through Varnish to backend
Uncached: Direct to backend with VirtualHostBase rewrite
Maintenance: Direct backend access with VirtualHostRoot
No Frontend Service¶
The manifest doesn’t include:
Frontend deployment
Frontend service
Frontend-to-backend internal routing
This makes the deployment ~15% smaller and simpler to manage.
Troubleshooting¶
Backend Not Starting¶
Check backend logs:
kubectl logs -l app.kubernetes.io/name=plone-backend -f
Common issues:
Database connection failures
Memory limits too low
Image pull errors
Classic UI Interface Not Loading¶
Check if backend pods are running:
kubectl get pods -l app.kubernetes.io/name=plone-backendVerify virtual host rewriting in ingress:
kubectl describe ingressCheck Varnish routing:
kubectl logs -l app.kubernetes.io/name=plone-httpcache
Add-on Compatibility¶
Some add-ons are Volto-specific. For Classic UI:
Use Classic UI themes (not Volto themes)
Check add-on compatibility with Plone 6 Classic UI
Avoid Volto-specific frontend add-ons
Migrating to Volto¶
If you want to migrate from Classic UI to Volto later:
Keep your backend deployment (same configuration)
Add Volto frontend from the Volto example
Update ingress to route to frontend
Both UIs can run simultaneously during migration
See the Production Volto deployment guide for details.
Customization¶
Backend Configuration¶
Edit main.ts to customize:
const plone = new Plone(this, 'plone', {
variant: PloneVariant.CLASSICUI,
backend: {
image: 'plone/plone-backend:6.1.3',
replicas: 2,
limitMemory: '1Gi',
limitCpu: '1000m',
environment: env,
},
})
Varnish Caching¶
Edit config/varnish.tpl.vcl for caching rules specific to Classic UI.
Classic UI VCL is simpler than Volto’s - all traffic routes to one backend.
Scaling¶
Scale backend replicas:
backend: {
replicas: 3, // Increase for higher traffic
}
Then:
npm run synth
kubectl apply -f dist/plone-classic.k8s.yaml
Performance¶
Classic UI performance characteristics:
Server-side rendering can be slower than Volto’s client-side
Varnish caching is critical for performance
Database is the main bottleneck (use CloudNativePG for HA)
Fewer HTTP requests than Volto (no separate frontend API calls)
Cleanup¶
kubectl delete -f dist/plone-classic.k8s.yaml
Next Steps¶
Configure CloudNativePG backups
Customize Classic UI theme
Set up content migration
See Also¶
Deploy Production Volto - For modern React UI
Setup Prerequisites - Cluster requirements
Configuration Options - API reference