Case study

Moving a live Formula 1 ticketing platform out of a disrupted AWS region

A Formula 1 circuit, via Browser London. Contract. 2025–2026. Sole engineer on the migration and the new stack.

Client
A Formula 1 circuit, via Browser London
Role
Sole engineer on the migration and the new stack
Period
2025–2026
Engagement
Contract

Client context

The client is a Formula 1 circuit. Its public site has two parts. One is a WordPress marketing site in English and Arabic. The other is a custom PHP ticketing application on the AudienceView ticketing API. The ticketing app has no database of its own. It turns web requests into ticketing API calls and renders the results.

The region went down

In March 2026 strikes on AWS facilities disrupted the Bahrain region (me-south-1). The platform's whole AWS estate ran there. I moved it to Ireland (eu-west-1) over March and April 2026. I did all of the migration myself. No S3 buckets were lost in the move.

Why it needed a new stack anyway

The old platform ran one PHP 7.4 container as six ECS tasks on EC2. PHP 7.4 reached end of life in November 2022. In August 2026 a routine media plugin update required PHP 8.1. It broke every image on the site. The tasks and the load balancer stayed healthy, so no health check caught it. I rolled the image back. The runtime was now blocking routine security updates. The stack could no longer be maintained without being changed.

The new architecture

I re-architected the platform on Amazon ECS with AWS Fargate.

  • Two services: the CMS and the ticketing app. A WordPress plugin update can no longer take ticketing offline. Each service scales on its own.
  • WordPress on Bedrock. Core and every plugin are pinned with Composer. A plugin update is now a one-line, reviewable change.
  • PHP 8.3 and a major WordPress upgrade.
  • Configuration from SSM Parameter Store. No secrets in the repository.
  • Amazon ElastiCache for Valkey holds sessions and cache.
  • Amazon RDS for the CMS database. Media in S3, served through CloudFront.
  • CloudFront and AWS WAF in front. The load balancer accepts traffic only from CloudFront.
  • Cutover by Application Load Balancer rule. Rollback takes seconds. The old platform stayed in place as a rollback target.

The main site moved to the new stack in August 2026. I recorded each design decision as an architecture decision record.

Two panels. Before: users reach an Application Load Balancer, which sends traffic to one PHP 7.4 container running WordPress and ticketing as six ECS tasks on EC2. The container talks to Amazon RDS for MySQL. Media is in S3, served through CloudFront. AWS WAF has a rate-limit rule. After: users reach CloudFront with AWS WAF, then an Application Load Balancer that accepts CloudFront only on port 443. Path routing sends /tickets to a ticketing service and everything else to a CMS service. Both are ECS services on AWS Fargate. The CMS service runs WordPress on Bedrock with PHP 8.3 and uses Amazon RDS for MySQL, with media in S3. The ticketing service runs PHP 8.3 with no database and calls the AudienceView ticketing API. Both services use ElastiCache for Valkey, SSM Parameter Store, and CloudWatch. A Queue-it connector on Lambda@Edge is attached to CloudFront, pre-staged and enabled by one change. Bitbucket Pipelines deploys through OIDC to an IAM role to ECS, with a manual approval gate before production.
Before and after. Before: one container, so a plugin update could take ticketing down. After: two Fargate services behind CloudFront.

Delivery and observability

I rebuilt CI/CD on Bitbucket Pipelines. Each image is built once. OIDC to AWS replaced a static access key. Every production deploy waits for a manual approval. I wrote the deploy and rollback runbooks.

I built the observability layer in CloudWatch: structured JSON logs, metric filters, alarms, and a dashboard. The definitions live in the repository.

The August 2026 on-sale

In August 2026 the platform sold tickets for a Formula 1 race weekend. I ran production through the on-sale.

  • The day before launch, the database saturated for 14 minutes. I traced it to a single scanning IP address. It was making thousands of requests for missing pages, and each one ran uncached. I tightened the WAF rules. I locked the load balancer so it accepts traffic only from CloudFront. I replaced long-lived AWS keys with task roles.
  • I found and fixed several classes of server error. The largest single fix cut server errors by about 85 percent.
  • I load-tested with k6. The ceiling was about 11 requests per second at the ticketing vendor's API. Our containers were not the limit.
  • I pre-staged a Queue-it waiting room as a Lambda@Edge connector. Turning it on is one reversible CloudFront change. It needs no software release.
  • I found a session-cookie defect. Our client code cut the vendor's session cookie short by 17 characters. About two thirds of ticketing calls failed as a result. After the fix, pricing calls went from 3 of 8 succeeding to 10 of 10.

The September 2026 on-sale

On 30 September 2026 tickets for the next Formula 1 season went on sale on the new stack. A Queue-it waiting room was live for the event. Card payments had been stalling after the 3-D Secure device check. The 3-D Secure provider had moved that check to a new host. Our page only trusted the old one. I fixed it before the sale. On the day I shipped a card-form hotfix. Form rejections fell from 82 of 88 submits to 0 of 5.

Timeline with six points. March 2026: AWS Bahrain region me-south-1 disrupted. March to April 2026: whole AWS estate moved to Ireland, eu-west-1. 6 August 2026: on-sale launch day on the old stack. 7 August 2026: a plugin outage proves the PHP 7.4 stack cannot be maintained, and the new stack is decided and scaffolded. August 2026: main site cut over to the Fargate stack; on 28 August the session-cookie fix reached production and the load balancer was locked to CloudFront. 30 September 2026: next season's on-sale runs on the new stack with a live Queue-it waiting room.
Timeline, March to September 2026.

How I work on it

I operate the platform with an AI coding agent (Claude Code) under written guardrails I authored. Nothing deploys straight to production. Changes go to UAT first. AWS profile rules are fixed. No secrets go in config. Decisions live in ADRs. Procedures live in runbooks.

Stack

  • Amazon ECS
  • AWS Fargate
  • ALB
  • CloudFront
  • AWS WAF
  • Lambda@Edge
  • RDS
  • S3
  • ElastiCache (Valkey)
  • SSM Parameter Store
  • CloudWatch
  • IAM OIDC
  • Docker
  • Bitbucket Pipelines
  • k6
  • WordPress
  • Bedrock
  • Composer
  • PHP 8.3
  • WPML
  • AudienceView API
  • Queue-it