Django 4.2部署AWS:collectstatic未上传静态文件至S3求助
核心问题
从日志显示1084 static files copied to '/var/app/current/static',以及后续的NoSuchKey错误可以明确:静态文件根本没有上传到S3桶,collectstatic仅完成了本地复制,后续页面请求的S3路径自然找不到文件。以下是针对性的排查和修复步骤:
1. 修复USE_S3的判断逻辑
你的USE_S3 = os.getenv('LOGNAME') == 'webapp'依赖执行collectstatic的用户是否为webapp,但Elastic Beanstalk默认执行该命令的用户是root或ec2-user,而非webapp,这直接导致USE_S3为False,触发本地静态文件配置,不会上传到S3。
修复方案:
改用环境变量控制USE_S3,比如在EB环境变量中添加USE_S3=True,然后修改配置:
USE_S3 = os.getenv('USE_S3') == 'True'
2. 修正STORAGES配置的OPTIONS位置
Django 4.2的STORAGES配置中,OPTIONS是每个存储后端的子属性,你当前把OPTIONS放在了STORAGES根节点,导致自定义存储类无法读取S3配置参数,无法正常连接S3。
正确配置示例:
STORAGES = { "default": { "BACKEND": 'custom_storages.MediaStorage', "OPTIONS": { "bucket_name": AWS_STORAGE_BUCKET_NAME, "region_name": AWS_S3_REGION_NAME, "verify": AWS_S3_VERIFY, "signature_version": AWS_S3_SIGNATURE_VERSION, "cloudfront_key_id": AWS_CLOUDFRONT_KEY_ID, "cloudfront_key": AWS_CLOUDFRONT_KEY, }, }, "staticfiles": { "BACKEND": 'custom_storages.StaticStorage', "OPTIONS": { "bucket_name": AWS_STORAGE_BUCKET_NAME, "region_name": AWS_S3_REGION_NAME, "verify": AWS_S3_VERIFY, "signature_version": AWS_S3_SIGNATURE_VERSION, "cloudfront_key_id": AWS_CLOUDFRONT_KEY_ID, "cloudfront_key": AWS_CLOUDFRONT_KEY, }, }, }
3. 确认自定义存储类实现正确
确保custom_storages.py中的存储类正确继承S3Boto3Storage并设置location属性,否则无法指定S3中的存储路径:
from storages.backends.s3boto3 import S3Boto3Storage class StaticStorage(S3Boto3Storage): location = 'static' # 对应STATICFILES_LOCATION default_acl = None class MediaStorage(S3Boto3Storage): location = 'media' # 对应MEDIAFILES_LOCATION default_acl = None
4. 补充EB实例的IAM权限
你的S3桶策略仅允许CloudFront服务主体读写,但EB实例执行collectstatic需要自身的IAM角色具备S3上传权限。给EB实例的IAM角色添加以下权限策略:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::<你的S3桶名>", "arn:aws:s3:::<你的S3桶名>/*" ] } ] }
5. 手动验证collectstatic上传
登录到EB实例,切换到应用目录,执行:
sudo su webapp python manage.py collectstatic --noinput
执行后查看S3桶中是否出现static目录及对应文件,同时观察命令输出是否有报错,定位具体问题。
关于之前的权限错误
之前出现的Query-string authentication requires the Signature, Expires and AWSAccessKeyId parameters错误,是因为你开启了AWS_QUERYSTRING_AUTH = True,但生成的URL缺少签名参数,这也是因为存储类配置错误导致的,修复上述配置后该问题会同步解决。
内容的提问来源于stack exchange,提问作者Lawrence DeSouza

