Déployer une application Django qui utilise AWS S3 pour gérer ses fichiers médias et fichiers statiques semble, au premier abord, une formalité.

Pourtant, quand on se lance vraiment, les surprises arrivent vite :

  • erreurs Access Denied,

  • problèmes avec les ACL,

  • Bucket Policies trop restrictives,

  • tableau de bord Django sans style CSS,

  • erreurs silencieuses à l'upload,

  • incompréhension de la gestion de l'accès public sur S3.

En tant que développeur, je voulais rendre mon projet plus scalable, plus propre, en hébergeant tous mes médias et fichiers statiques sur AWS S3, plutôt que de tout laisser sur le serveur local.

Je partage ici tout mon cheminement, mes erreurs, et surtout comment je les ai corrigées, pour obtenir une intégration fiable, rapide, et sécurisée.

1. Création du Bucket S3

Première étape, créer un bucket S3.

Je me connecte à AWS Management Console > S3 > Créer un bucket.

Piège n°1 : les paramètres de blocage d'accès public

Par défaut, AWS recommande de bloquer tous les accès publics. Ce que j'ai fait.

Problème ?

Si tout est bloqué, Django, mon frontend et même moi n'avons plus accès aux fichiers !

Solution :

Je laisse coché "Bloquer toutes les ACL (anciennes et nouvelles)" ✅.

Mais je décoche "Bloquer l'accès public via Bucket Policies" ❌.

Ainsi, je gère tout l'accès public à travers une Bucket Policy.

2. Configuration de la Bucket Policy

Deuxième étape, permettre l'accès en lecture publique.

Je mets cette Bucket Policy sur mon bucket :

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowPublicReadAccessToObjects",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::mon-bucket-name/*"
    }
  ]
}

3. Création de l'utilisateur IAM et des clés d'accès

Je crée un utilisateur IAM dans AWS Console :

Accès programmatique uniquement.

Permission AmazonS3FullAccess (temporairement pour tout mettre en place).

Je récupère :

AWS_ACCESS_KEY_ID

AWS_SECRET_ACCESS_KEY

À mettre ensuite dans Django.

4. Configuration Django pour utiliser S3

Dans ton settings :

AWS_ACCESS_KEY_ID = '...'
AWS_SECRET_ACCESS_KEY = '...'
AWS_STORAGE_BUCKET_NAME = 'mon-bucket-name'
AWS_S3_REGION_NAME = 'eu-north-1'
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.{AWS_S3_REGION_NAME}.amazonaws.com'

STATICFILES_STORAGE = 'storage.StaticStorage'
DEFAULT_FILE_STORAGE = 'storage.MediaStorage'

STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/static/'
MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/media/'

Dans ton fichier storage :

from storages.backends.s3boto3 import S3Boto3Storage

class StaticStorage(S3Boto3Storage):
    location = 'static'
    default_acl = 'public-read'

class MediaStorage(S3Boto3Storage):
    location = 'media'
    default_acl = 'public-read'

Tu crée ton fichier upload_media pour ne pas ecraser tes fichiers existant

import boto3
import os
from django.conf import settings
from django.core.management.base import BaseCommand


def upload_media_to_s3():
    s3_client = boto3.client(
        's3',
        aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
        aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
        region_name=settings.AWS_S3_REGION_NAME
    )

    media_root = settings.MEDIA_ROOT
    for root, dirs, files in os.walk(media_root):
        for file in files:
            local_path = os.path.join(root, file)
            relative_path = os.path.relpath(local_path, media_root)
            s3_path = os.path.join('media', relative_path)

            s3_client.upload_file(
                local_path,
                settings.AWS_STORAGE_BUCKET_NAME,
                s3_path
            )
            print(f"Uploaded {local_path} to {s3_path}")


if __name__ == "__main__":
    import django

    django.setup()
    upload_media_to_s3()

5. Problèmes rencontrés et solutions

Problème 1 : AccessDenied en accédant aux fichiers

Corrigé en mettant une Bucket Policy propre.

Problème 2 : AccessControlListNotSupported

Mon bucket était configuré avec "Bucket owner enforced".

J'ai supprimé l'option --acl public-read dans AWS CLI.

Problème 3 : tableau de bord Django sans CSS

J'ai oublié d'envoyer mes fichiers staticfiles/ sur S3.

Solution :

python manage.py collectstatic
aws s3 cp staticfiles/ s3://mon-bucket-name/static/ --recursive

6. Script automatique pour uploader les fichiers statiques

J'ai créé un petit script Bash upload_static.sh :

#!/bin/bash

python manage.py collectstatic --noinput
aws s3 cp staticfiles/ s3://mon-bucket-name/static/ --recursive

Exécution :
./upload_static.sh

Simple et efficace !

Conclusion

Intégrer Django avec AWS S3 demande de comprendre quelques subtilités :

  • Comment S3 gère l'accès public,

  • Comment fonctionnent les ACL et Bucket Policies,

  • Comment organiser ses fichiers statiques et médias,

Comment anticiper les erreurs AccessDenied et AccessControlListNotSupported.

Grâce à ce parcours et à ces solutions, j'ai pu rendre mon application plus rapide, plus robuste et prête à scaler.

Si toi aussi tu construis ton projet Django sur AWS, j'espère que ce guide t'évitera de nombreuses heures de galère ! 🚀

Bon déploiement à toi 👋 !