My Brain
My Brain

AWS S3 setup

On AWS

  1. Create a new bucket on AWS S3.

  2. Uncheck Block all public access.

  3. Click Create bucket.

  4. Go to the bucket's properties tab and select Static website hosting (Use this bucket to host a website).

  5. Enter the defaults index.html and error.html and click save.

  6. Go to permissions and then CORS configurations.

  7. Enter one in JSON format. Such as:

    [
        {
            "AllowedHeaders": [
                "*"
            ],
            "AllowedMethods": [
                "GET",
                "POST",
                "PUT"
            ],
            "AllowedOrigins": [
                "*"
            ],
            "ExposeHeaders": [],
            "MaxAgeSeconds": 3000
        }
    ]
  8. Go to the Bucket policy tab and select Policy generator:

    1. Select Type of Policy: S3 Bucket Policy
    2. Principal: *
    3. AWS Service: Amazon S3
    4. Actions: Get object
    5. Amazon Resource Name (ARN): copy and paste the ARN from the bucket.
    6. Add statement
    7. Generate Policy
    8. Copy the policy and paste it in the bucket policy tab, making sure to add a /* at the end of the resource key
  9. Go to the Access Controls List tab and set the list objects permissions selected for everyone and save.

  10. In a new tab go to IAM in AWS.

  11. Select Groups and create a new one called whatever you want, preferably related to our project.

  12. Click through and finally Create group.

  13. Click on Policies on the meny on the left, and then Create policy.

  14. Select the JSON tab and click on Import managed policy.

  15. Search and import AmazonS3FullAccesss policy.

  16. Replace "*" with your ARN followed by the ARN/*, such as:

    {
        "Resource": [
            "your_ARN",
            "your_ARN/*"
        ]
    }
  17. Click on Review Policy and give it a name and description, then click Create policy.

  18. Click on gourps, select your previously created group, click Attach policy, search for the just created policy, select it and click on Attach policy.

  19. Go to Users, add an user and give it a related name.

  20. Give it Programmatic access under Access type, click on Next: permissions and select the group created previously, clicking through the end until clicking Create user.

  21. Download the .csv file which contains the keys necessary (that's the only opportunity to save that information!) and click on close.

On the code editor

  1. Install boto3 and django-storages with pip.

  2. add storages to your installed apps.

  3. in settings.py, add:

    if "USE_AWS" in os.environ:
        AWS_S3_OBJECT_PARAMETERS = {
            "Expires": "Thu, 31 Dec 2099 20:00:00 GMT",
            "CacheControl": "max-age=94608000",
        }
        AWS_STORAGE_BUCKET_NAME = "your_bucket_name"
        AWS_S3_REGION_NAME = "eu-central-1"  # or your timezone
        AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID")  # to be added to Heroku - take from .csv
        AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY")  # to be added to Heroku - take from .csv
        AWS_S3_CUSTOM_DOMAIN = f"{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com"
  4. Add the two keys to Heroku's variables, plus USE_AWS=True.

  5. Create a fille at root level in the app called custom_storages.py:

    from django.conf import settings
    from storages.backends.s3boto3 import S3Boto3Storage
    
    class StaticStorage(S3Boto3Storage):
        location = settings.STATICFILES_LOCATION
    
    class MediaStorage(S3Boto3Storage):
        location = settings.MEDIAFILES_LOCATION
  6. Continuing on settings.py:

        STATICFILES_STORAGE = "custom_storages.StaticStorage"  # uses the class just created
        STATICFILES_LOCATION = "static"
        DEFAULT_FILE_STORAGE = "custom_storages.MediaStorage"  # uses the class just created
        MEDIAFILES_LOCATION = "media"
        STATIC_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/{STATICFILES_LOCATION}/"  # explicitly declares and overrides location
        MEDIA_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/{MEDIAFILES_LOCATION}/"  # explicitly declares and overrides location
  7. Add in heroku the variable DISABLE_COLLECTSTATIC=1 so it won't collect it automatically. You can manually collect it with heroku run bash and python manage.py collectstatic. This prevents collecting static on each deploy.

  8. Run collectstatic as instructed in 7, and check that AWS created the static folder.

  9. Add optional setting on settings.py:

        AWS_S3_OBJECT_PARAMETERS = {
            "Expires": "Thu, 31 Dec 2099 20:00:00 GMT",
            "CacheControl": "max-age=94608000",
        }
  10. Back in AWS, open the bucket and create a folder called media.

  11. Copy to it all media files present in your project.

  12. If prompted, grant public permissions to the files to be uploaded.

  13. Add email variables to settings.py and Heroku in order to receive emails related to account management:

    if "DEBUG" in os.environ:
        EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
        DEFAULT_FROM_EMAIL = "brachetta@me.com"
    else:
        EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
        EMAIL_USE_TLS = True
        EMAIL_PORT = 587
        EMAIL_HOST = "smtp.strato.com"
        EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER")
        EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASS")
        DEFAULT_FROM_EMAIL = os.environ.get("EMAIL_HOST_USER")
  14. The resulting settings in settings.py should be:

    if "USE_AWS" in os.environ:
        AWS_S3_OBJECT_PARAMETERS = {
            "Expires": "Thu, 31 Dec 2099 20:00:00 GMT",
            "CacheControl": "max-age=94608000",
        }
        AWS_STORAGE_BUCKET_NAME = "your_bucket"
        AWS_S3_REGION_NAME = "eu-central-1"
        AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID")
        AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY")
        AWS_S3_CUSTOM_DOMAIN = f"{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com"
        STATICFILES_STORAGE = "custom_storages.StaticStorage"
        STATICFILES_LOCATION = "static"
        DEFAULT_FILE_STORAGE = "custom_storages.MediaStorage"
        MEDIAFILES_LOCATION = "media"
        STATIC_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/{STATICFILES_LOCATION}/"
        MEDIA_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/{MEDIAFILES_LOCATION}/"
    
    STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
    STATIC_URL = "/static/"
    STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)
    
    MEDIA_URL = "/media/"
    MEDIA_ROOT = os.path.join(BASE_DIR, "media")
    
    MESSAGE_TAGS = {messages.ERROR: "danger"}
    
    if "DEVELOPMENT" in os.environ:
        EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
        DEFAULT_FROM_EMAIL = "brachetta@me.com"
    else:
        EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
        EMAIL_USE_TLS = True
        EMAIL_PORT = 587
        EMAIL_HOST = "smtp.strato.com"  # your email host here
        EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER")
        EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASS")
        DEFAULT_FROM_EMAIL = os.environ.get("EMAIL_HOST_USER")
  15. Remember to add the static folder location to the main urls.py:

    urlpatterns = [
        ...
    ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Backlinks