Architecture Overview¶
This document explains how kup6s-pages components work together to provide multi-tenant static site hosting.
Components¶
pages-operator¶
The operator watches StaticSite CRDs across all namespaces and manages:
Traefik IngressRoutes - Route traffic to nginx based on domain
Traefik Middlewares - addPrefix middleware for efficient routing
cert-manager Certificates - Automatic TLS for custom domains
Key behaviors:
Uses ClusterRole to watch StaticSites in any namespace
Creates resources in the same namespace as the StaticSite
Shares certificates between sites using the same domain
pages-syncer¶
The syncer clones and pulls Git repositories:
Periodic sync - Polls repositories at configurable intervals (default 5m)
Webhook sync - Instant updates on git push
Secret access - Reads deploy tokens from the StaticSite’s namespace
Status updates - Updates StaticSite status with sync progress
Storage layout:
/sites/
├── my-website/ # Direct clone (no subpath)
├── .repos/
│ └── docs/ # Full clone when using subpath
│ └── dist/ # Build output
└── docs -> .repos/docs/dist/ # Symlink for subpath serving
nginx¶
A single nginx pod serves all static sites:
Shared PVC - ReadWriteMany storage shared with syncer
Simple config - Static
root /sites;with try_filesHA ready - Multiple replicas with pod anti-affinity
Request Flow¶
Client requests
https://www.example.com/about.htmlTraefik matches
Host(\www.example.com`)` IngressRouteMiddleware adds prefix:
/my-website/about.htmlnginx serves
/sites/my-website/about.htmlfrom PVC
Cross-Namespace Design¶
kup6s-pages namespace (central)
├── pages-operator → ClusterRole (watches all namespaces)
├── pages-syncer → ClusterRole (reads secrets from any namespace)
├── nginx → Serves from shared PVC
└── PVC: sites-data → ReadWriteMany storage
customer-app namespace
├── StaticSite CRD → Created by user
├── Secret (optional) → Git credentials (read by syncer)
├── IngressRoute → Created by operator
├── Middleware → Created by operator
└── Certificate → Created by operator (for custom domains)
Storage Requirements¶
The PVC must support ReadWriteMany (RWX) access mode since both syncer and nginx pods need concurrent access. In this cluster, the storagebox StorageClass (SMB CSI) provides RWX support.
Why addPrefix?¶
Instead of reconfiguring nginx for each site, we use Traefik’s addPrefix middleware:
No nginx reloads - Adding a site doesn’t restart nginx
No race conditions - ConfigMap updates can cause pod restarts
Simple nginx config - Static configuration never changes
Efficient routing - Traefik handles dynamic routing
This design allows scaling to hundreds of sites with minimal resource overhead.