Institutional Web Infrastructure on AWS
Full design and deployment of a hybrid cloud architecture for a high-traffic institutional portal, developed in partnership with a systems integrator. The project encompassed a global CDN layer with intelligent path-based routing, a multi-layer caching strategy with automatic invalidation, and a shared persistent filesystem model supporting simultaneous access from containerized workloads and CI/CD pipelines.
Architecture Overview
Context and Challenge
A large-scale institutional portal ran its workloads entirely on-premise, with multiple Docker services exposed independently, no centralized entry point and no CDN layer. Users in different geographic regions experienced inconsistent latency, and the absence of DDoS protection left the infrastructure exposed to volumetric attacks. Three independent sources could modify application files simultaneously: a CI/CD pipeline deploying theme and plugin updates, administrators making changes through the WordPress control panel, and periodic Docker image rebuilds updating the WordPress core. Each of these sources changed file contents without changing the file URLs, while the CDN cache lifetime for CSS and JavaScript assets was configured to one year. The result was that after every deployment, visitors continued to receive outdated stylesheets and scripts until the cache expired naturally.
Solution
The architecture was redesigned around three main pillars. The first pillar established AWS CloudFront as the single global entry point for all traffic, backed by an Application Load Balancer with path-based routing rules that distribute requests intelligently between cloud resources and the on-premise Docker services. This eliminated independent service exposure and centralized SSL termination, WAF inspection and DDoS mitigation in a single layer.
The second pillar addressed the stale cache problem through a two-part fix that both sides had to implement simultaneously. On the application side, the W3 Total Cache plugin was configured to append version hashes to all asset URLs. On the CDN side, a custom CloudFront cache policy was created with QueryStringBehavior set to all, so that the distribution includes query strings in the cache key. Without this second change, CloudFront would strip the version hashes from the cache key and serve the same cached file regardless of the version parameter, silently nullifying the cache-busting strategy. With both changes in place, a one-year cache lifetime becomes safe and optimal: unchanged files are served instantly from the edge, and when any file changes, its URL changes with it, making the old cache entry unreachable.
The third pillar solved the multi-consumer filesystem access problem. The WordPress containers running on Amazon ECS, the CI/CD pipeline operating through an EC2 instance, and the container entrypoint all needed simultaneous read and write access to the same Amazon EFS filesystem, but with different Linux UIDs. The solution applied the standard POSIX group permission model: all three consumers share the same supplemental group, files are owned by UID 1001 with group users and permissions 775 for directories and 664 for files. The Apache worker process, which ran as a different UID, was added to the shared group inside the Docker image with a single usermod command. No elevated permissions, no open permissions and no privilege escalation were required.
Cache Architecture
Rendered HTML stored in ElastiCache. Requests are served without executing PHP or querying the database.
Database queries and PHP objects cached in Redis. Volatile groups such as session data and counters are excluded from persistence.
Cache-Control with public max-age combined with ETag and Last-Modified headers. Safe because cache busting changes the URL whenever file content changes.
Static assets served from the nearest edge location. Custom cache policy with QueryStringBehavior: all ensures version hashes are part of the cache key.
Key Technical Decisions
Reducing TTL to 7 days without cache busting would force the CDN to re-fetch every asset weekly even when nothing changed. With version hashes in URLs, a one-year TTL maximizes edge cache hit rates while guaranteeing that changes propagate immediately.
Amazon EFS Access Points add operational complexity. The POSIX group approach achieves the same access control with a single usermod in the Dockerfile and standard filesystem permissions, with zero changes to ECS task definitions.
A full migration to AWS was not required. ALB path-based routing allows each service to remain on-premise while benefiting from a global CDN front, centralized security controls and AWS storage layers.
Implementation Highlights
browsercache.cssjs.replace: true browsercache.other.replace: true
aws cloudfront create-cache-policy \
--cache-policy-config '{
"Name": "CachingOptimized-WithQueryStrings",
"DefaultTTL": 86400,
"MaxTTL": 31536000,
"ParametersInCacheKeyAndForwardedToOrigin": {
"EnableAcceptEncodingGzip": true,
"EnableAcceptEncodingBrotli": true,
"QueryStringsConfig": { "QueryStringBehavior": "all" }
}
}' # Dockerfile
RUN usermod -aG users daemon
# EFS — set ownership and permissions
chown -R pipeline_user:users /mount/path/
find /mount/path/ -type d -exec chmod 775 {} \;
find /mount/path/ -type f -exec chmod 664 {} \;