YOUR DIGITAL HUB
← Retour au blog

Architecturer PHP sur AWS : du MVP au scale

· 11 min de lecture
Visuel de couverture — architecturer PHP sur AWS du MVP au scale

Pourquoi AWS reste le choix par défaut en 2026

AWS reste la plateforme cloud par défaut sur laquelle nous déployons les applications PHP de nos clients entreprise. Trois raisons, que nous revalidons chaque année.

  • Breadth. Plus de 240 services, depuis l'EC2 classique jusqu'à Aurora Serverless v2 et Bedrock pour les modèles fondation. Ce que vous voulez construire existe en service managé.
  • Conformité. SOC 2, ISO 27001, HDS, PCI-DSS, FedRAMP. Les entreprises réglementées (banque, santé, assurance) trouvent les certifications qu'il leur faut.
  • Écosystème. Terraform, OpenTofu, CDK, Pulumi, l'outillage IaC est mature. Les talents AWS sont trois à cinq fois plus nombreux que les talents GCP ou Azure sur le marché français.

Les contreparties sont bien réelles. Les factures AWS savent surprendre (NAT Gateway, egress cross-AZ, S3 request costs). La complexité des VPC et de l'IAM est un coût d'entrée qu'il faut assumer. Et sur certains workloads simples, un Scaleway ou un OVHcloud managé font le travail pour moitié moins cher.

Cet article décrit comment nous architecturons une application PHP sur AWS selon trois paliers de maturité : MVP, Growth, Scale. Avec les services concrets, les coûts réels, le code qui va avec.

Palier 1, MVP (0 à 10 000 utilisateurs)

Objectif : aller en production vite, sans sur-ingénierie. Une instance EC2 suffit, le multi-AZ est un sur-coût injustifié à ce stade. On garde néanmoins une discipline IaC et une base solide pour évoluer.

 Utilisateurs
      │
      ▼
 ┌──────────┐      ┌──────────────┐
 │ Route53  │─────▶│  CloudFront  │
 └──────────┘      └──────┬───────┘
                          │
                          ▼
                   ┌──────────────┐
                   │  EC2 t3.medium│
                   │  Nginx+PHP-FPM│
                   └──────┬────────┘
                          │
                ┌─────────┴─────────┐
                ▼                    ▼
          ┌──────────┐         ┌──────────┐
          │ RDS PG    │         │    S3    │
          │ db.t4g.micro│       │ uploads  │
          └──────────┘         └──────────┘
  • Compute : 1 instance EC2 t3.medium (ou t4g.medium Graviton pour -20 %). Nginx + PHP-FPM 8.3, Supervisor pour les workers.
  • Base de données : RDS PostgreSQL db.t4g.micro ou db.t4g.small. Backups automatiques 7 jours.
  • CDN et TLS : CloudFront devant le site, ACM pour le certificat, Route53 pour le DNS.
  • Assets : S3 pour les uploads utilisateurs, servis via CloudFront.
  • Emails : SES pour transactionnel, SNS pour alertes internes.
  • Monitoring : CloudWatch Logs + 3 alarmes (CPU, erreurs HTTP 5xx, disque).

Coût mensuel typique à ce palier : 80 à 150 €, hors SES (variable selon volume).

Le piège classique à éviter : ne pas se jeter sur RDS Multi-AZ (+100 % sur la facture DB) tant que le SLO ne l'exige pas. Un snapshot quotidien + un script de restore testé suffisent pour une app B2B en MVP.

Palier 2, Growth (10 000 à 500 000 utilisateurs)

On encaisse de la charge, des pics, et la disponibilité devient un vrai engagement. Multi-AZ partout sur les services stateful, horizontalité sur le compute, session Redis pour dégager PHP-FPM de l'état.

          Utilisateurs
               │
               ▼
        ┌──────────────┐
        │  CloudFront  │
        └──────┬───────┘
               │
               ▼
        ┌──────────────┐
        │     ALB      │
        └──────┬───────┘
               │
         Auto Scaling Group
         ┌─────┴─────┬─────────┐
         ▼           ▼         ▼
     ┌───────┐   ┌───────┐ ┌───────┐
     │ EC2-A │   │ EC2-B │ │ EC2-C │
     └───┬───┘   └───┬───┘ └───┬───┘
         └─────┬─────┴─────────┘
               │
       ┌───────┼────────────┐
       ▼       ▼            ▼
 ┌─────────┐ ┌───────────┐ ┌──────┐
 │RDS MAZ  │ │ElastiCache│ │  S3  │
 │PostgreSQL│ │  Redis    │ │      │
 └─────────┘ └───────────┘ └──────┘
  • Compute : ALB + Auto Scaling Group avec 2 à 6 instances EC2 m6i.large (ou m7g.large Graviton). Deux zones de disponibilité minimum.
  • Base de données : RDS PostgreSQL Multi-AZ, db.m6g.large avec 100 Go gp3 et IOPS provisionnés si nécessaire.
  • Cache et session : ElastiCache Redis 7, mode Cluster, deux nœuds, session PHP déportée (php.ini: session.save_handler = redis).
  • Assets et uploads : S3 + CloudFront.
  • Queue : SQS pour les jobs asynchrones (envoi d'emails, webhooks, traitements en arrière-plan).
  • Crons : EventBridge Scheduler déclenchant des Lambdas ou des tâches ECS à la demande.
  • Observabilité : CloudWatch Logs Insights, CloudWatch Metrics, X-Ray pour le tracing, dashboards et alarmes SLO.

Coût mensuel typique : 400 à 800 €. Les gros postes sont l'ASG EC2, RDS Multi-AZ et le trafic CloudFront.

À ce palier, nous containerisons systématiquement l'application, même si elle tourne encore en AMI. Le Dockerfile devient l'interface de déploiement, ce qui prépare le saut vers Fargate au palier suivant.

Palier 3, Scale (500 000 utilisateurs et plus)

Multi-région de lecture ou disaster recovery, services managés partout, auto-scaling fin, observabilité premier plan.

  • Compute : ECS Fargate (ou EKS si l'équipe est kube-native) avec service auto-scaling basé sur les métriques ALB et CloudWatch.
  • Base de données : Aurora PostgreSQL Serverless v2, read replicas multi-AZ, Aurora Global Database si cross-région nécessaire.
  • Cache : ElastiCache Redis cluster mode enabled, 3 shards minimum, réplication cross-AZ.
  • Recherche : OpenSearch managé ou OpenSearch Serverless.
  • Asynchrone : SQS + Lambda pour traitements courts, ECS tasks pour traitements longs.
  • Batch : AWS Batch ou ECS scheduled tasks, parfois Step Functions pour orchestrer.
  • CDN : CloudFront avec origin shield, Lambda@Edge pour les règles de routage ou d'A/B testing.
  • WAF : AWS WAF devant CloudFront et l'ALB, règles managées OWASP + règles bot control.
  • Observabilité : Prometheus et Grafana sur EKS pour les équipes kube, ou Managed Grafana + Managed Prometheus, Datadog ou New Relic selon choix ops.

Coût mensuel typique : 2 000 à 10 000 € selon volumétrie. Sur un client traitant 20 M de requêtes par jour, nous sommes à 6 500 € par mois en régime stable.

Dockerfile PHP-FPM production-ready

Le conteneur PHP est le socle du déploiement. Voici la base que nous utilisons et durcissons projet par projet.

# syntax=docker/dockerfile:1.7

FROM php:8.3-fpm-alpine AS base

RUN apk add --no-cache \
        icu-libs \
        libpq \
        libzip \
        oniguruma \
        tzdata \
    && docker-php-ext-install -j$(nproc) \
        bcmath \
        intl \
        opcache \
        pcntl \
        pdo_pgsql \
        zip \
    && pecl install redis apcu \
    && docker-php-ext-enable redis apcu

RUN { \
        echo 'opcache.enable=1'; \
        echo 'opcache.enable_cli=0'; \
        echo 'opcache.memory_consumption=256'; \
        echo 'opcache.interned_strings_buffer=32'; \
        echo 'opcache.max_accelerated_files=20000'; \
        echo 'opcache.validate_timestamps=0'; \
        echo 'opcache.preload=/app/config/preload.php'; \
        echo 'opcache.preload_user=www-data'; \
        echo 'realpath_cache_size=4096k'; \
        echo 'realpath_cache_ttl=600'; \
    } > /usr/local/etc/php/conf.d/99-opcache-prod.ini

COPY --from=composer:2.8 /usr/bin/composer /usr/bin/composer

FROM base AS deps
WORKDIR /app
COPY composer.json composer.lock symfony.lock ./
RUN composer install --no-dev --no-scripts --prefer-dist --no-progress --no-interaction

FROM base AS runtime
WORKDIR /app
COPY --from=deps /app/vendor ./vendor
COPY . .
RUN composer dump-autoload --optimize --classmap-authoritative --no-dev \
    && php bin/console cache:warmup --env=prod --no-debug \
    && chown -R www-data:www-data var public

USER www-data
EXPOSE 9000

HEALTHCHECK --interval=30s --timeout=3s --start-period=20s \
    CMD SCRIPT_NAME=/health SCRIPT_FILENAME=/health REQUEST_METHOD=GET \
        cgi-fcgi -bind -connect 127.0.0.1:9000 || exit 1

CMD ["php-fpm", "-F"]

Trois choses non négociables dans nos Dockerfiles de prod :

  • Multi-stage pour ne pas embarquer Composer et les devDependencies dans l'image finale.
  • OPcache durci avec validate_timestamps=0 et preload Symfony. Gain de latence systématique de 10 à 30 %.
  • User non-root (www-data). Nous refusons les images qui tournent en root.

Sur ECS Fargate, ce conteneur tourne dans une task avec un sidecar Nginx (nginx:1.27-alpine) partageant un volume éphémère sur lequel Symfony a copié public/.

Module Terraform pour un service Fargate PHP

Nous maintenons un module Terraform réutilisable pour déployer un service PHP sur ECS Fargate avec ALB, service auto-scaling et logs. Voici un extrait représentatif.

module "php_service" {
  source  = "./modules/fargate-php"

  name          = "invoicing-api"
  cluster_arn   = aws_ecs_cluster.main.arn
  vpc_id        = module.vpc.vpc_id
  private_subnets = module.vpc.private_subnets
  public_subnets  = module.vpc.public_subnets

  container_image = "${aws_ecr_repository.app.repository_url}:${var.image_tag}"
  cpu             = 1024
  memory          = 2048

  desired_count = 3
  min_capacity  = 3
  max_capacity  = 20
  target_cpu    = 60
  target_alb_rps = 400

  environment = {
    APP_ENV = "prod"
    APP_DEBUG = "0"
  }

  secrets = {
    APP_SECRET          = aws_secretsmanager_secret.app_secret.arn
    DATABASE_URL        = aws_secretsmanager_secret.database_url.arn
    REDIS_URL           = aws_secretsmanager_secret.redis_url.arn
    ANTHROPIC_API_KEY   = aws_secretsmanager_secret.anthropic.arn
  }

  log_retention_days = 30
  enable_xray        = true
  alb_health_path    = "/health"

  tags = {
    Project     = "invoicing"
    Environment = "prod"
    ManagedBy   = "terraform"
  }
}

Le module encapsule un paquet de best practices :

  • Task role IAM au périmètre minimal.
  • Secrets tirés depuis Secrets Manager, jamais en clair dans la task definition.
  • Service discovery via Cloud Map si plusieurs services communiquent en interne.
  • Auto-scaling cible par CPU ET par RPS ALB, avec cooldown à 60 secondes.
  • Sidecar X-Ray activé si enable_xray = true.
  • Log group dédié par service, rétention configurable.

Spécificités PHP sur AWS

  • Sessions : déporter via Redis dès qu'il y a plus d'une instance. session.save_handler = redis, session.save_path = tcp://redis:6379.
  • File uploads : ne jamais écrire sur le disque de la task. Uploads directs S3 (presigned POST) ou upload côté app puis putObject vers S3 et purge du tmp.
  • Logs applicatifs : Monolog en JSON stdout, CloudWatch Logs capte la sortie du conteneur, Logs Insights pour les recherches.
  • Crons : EventBridge Scheduler + tâche ECS run-task. Ne jamais laisser un cron crontab dans un conteneur, ça ne survit pas à l'auto-scaling.
  • Workers : un service ECS séparé consomme SQS (ex. bin/console messenger:consume).
  • Warmup : cache:warmup à la construction de l'image. Sur Fargate, chaque cold start pendant le scale-up coûte sans cette étape.

Sécurité AWS

Les règles minimales que nous ne négocions pas sur un workload PHP entreprise.

  • VPC avec subnets privés pour les tasks et les DB, subnets publics uniquement pour ALB et NAT Gateway.
  • Security groups au périmètre strict, pas de 0.0.0.0/0 inbound sur les tasks.
  • IAM least privilege : chaque task role a ses actions listées une à une, pas de *.
  • Secrets Manager pour les secrets dynamiques, KMS pour les clés de chiffrement.
  • RDS chiffré au repos (KMS), TLS en transit imposé côté driver.
  • CloudTrail activé sur tous les comptes, logs centralisés dans un compte audit.
  • GuardDuty activé, findings remontés vers Security Hub ou un SIEM externe.
  • AWS WAF devant CloudFront et l'ALB en prod.

Observabilité

Les quatre piliers pour un PHP en prod sur AWS :

  1. Logs : Monolog JSON → CloudWatch Logs → Logs Insights pour ad-hoc, export S3 pour long terme.
  2. Métriques : CloudWatch Metrics, custom metrics via PutMetricData ou EMF (embedded metric format). Dashboards par domaine métier.
  3. Traces : X-Ray SDK PHP pour tracer les appels aux DB, au cache, aux APIs externes. Ou OpenTelemetry si vous voulez rester neutre.
  4. Alerting : CloudWatch Alarms → SNS → Slack ou PagerDuty. Alertes basées SLO, pas sur la CPU brute.

Coûts réels et comment les réduire

Sur 20 missions AWS, les leviers qui comptent vraiment :

  • Graviton (ARM) : -20 à -40 % sur EC2, RDS, ElastiCache par rapport à Intel équivalent. La majorité des images PHP 8.3 tournent nativement en ARM depuis longtemps.
  • Savings Plans compute 3 ans no-upfront : -40 % environ sur le compute si la charge est stable.
  • Reserved Instances RDS 1 an no-upfront : -30 à -40 % sur la DB.
  • S3 Intelligent-Tiering pour les assets peu consultés.
  • CloudFront caching correct : le hit ratio doit être > 85 %, sinon on paie du transfer out EC2.
  • VPC Endpoints pour S3, DynamoDB, Secrets Manager : évite les NAT Gateway charges sur le traffic AWS interne.

Pièges classiques que nous débusquons en audit

  • NAT Gateway facturé sans le voir. 0,045 $ par Go processé + 0,045 $ par heure. Un workload qui parle beaucoup à Internet peut payer 500 à 1 500 € par mois juste sur le NAT.
  • RDS sur-dimensionné. Des instances db.r6g.xlarge tournant à 8 % de CPU. Revue trimestrielle obligatoire.
  • Transfer out cross-AZ. Souvent oublié. Un ALB qui balance sur 3 AZ avec des backends tout en cross-AZ traffic peut ajouter 10 à 15 % à la facture.
  • ALB idle. Plusieurs ALB "au cas où". Chacun coûte ~20 € par mois plus les LCUs. Consolider.
  • CloudWatch Logs en rétention infinie. 5 à 10 ans de logs sur Splunk interne. Rétention 30 jours + archive S3 suffit la plupart du temps.
  • EBS gp2. Toujours migrer vers gp3 (moins cher, meilleures perfs baseline).

Alternatives où AWS n'est pas le meilleur choix

  • Scaleway, OVHcloud pour un SaaS mono-région à budget serré : tarifs 2 à 3 fois plus bas sur le compute, souveraineté française, support en français.
  • GCP si vous utilisez déjà BigQuery ou Vertex AI. Cloud Run pour PHP containerisé est excellent.
  • Azure dans les environnements Microsoft-heavy (Active Directory, Office 365, Dynamics). L'intégration AAD et les licences liées peuvent justifier Azure même pour un PHP.
  • Platform.sh ou Clever Cloud pour les équipes qui ne veulent pas gérer d'infra du tout, sur des applications simples.

Conclusion

AWS est un excellent choix par défaut pour une application PHP d'entreprise en 2026, à condition de traiter les coûts avec la même rigueur que le code. Les trois paliers MVP, Growth, Scale structurent la trajectoire : on commence simple, on ajoute du managé au fur et à mesure de la croissance, on gagne en résilience et en élasticité sans sur-ingénierie prématurée.

Pour un cadrage AWS sur votre workload PHP, une migration on-premise vers AWS ou un audit de facture, écrivez-nous à contact@your-digital-hub.com ou découvrez nos prestations hébergement et DevOps.