0

absolute beginner here having an absolute nightmare deploying a tiny website to Heroku. I have worked through numerous issues to get to this point, but I now seem to have hit another wall. I have raised this as a support ticket with Heroku, but unless it is an issue on their side I doubt whether they will come back to me with a clear answer.

I can successfully deploy to Heroku, however, when opening up my web app I can only see the words "Internal Server Error" in place of my site. I receive an issue/error through to my Sentry log, which is as follows:

MESSAGE
ParamValidationError: Parameter validation failed:
Invalid bucket name "": Bucket name must match the regex "^[a-zA-Z0-9.\-_]{1,255}$"
EXCEPTION(most recent call first)App OnlyFullRaw
ParamValidationError
Parameter validation failed:
Invalid bucket name "": Bucket name must match the regex "^[a-zA-Z0-9.\-_]{1,255}$"
storages/backends/s3boto3.py in exists at line 478
    def exists(self, name):
        name = self._normalize_name(self._clean_name(name))
        if self.entries:
            return name in self.entries
        try:
            self.connection.meta.client.head_object(Bucket=self.bucket_name, Key=name)
            return True
        except ClientError:
            return False
    def listdir(self, name):
name    
'CACHE/css/cf136be60f95.css'
self    
<storages.backends.s3boto3.S3Boto3Storage object at 0x7fbe4b7f4e80>
compressor/base.py in output_file at line 321
        """
        The output method that saves the content to a file and renders
        the appropriate template with the file's URL.
        """
        new_filepath = self.get_filepath(content, basename=basename)
        if not self.storage.exists(new_filepath) or forced:
            self.storage.save(new_filepath, ContentFile(content.encode(self.charset)))
        url = mark_safe(self.storage.url(new_filepath))
        return self.render_output(mode, {"url": url})
    def output_inline(self, mode, content, forced=False, basename=None):
basename    
None
content 
'/*!
 * Material Design for Bootstrap 4
 * Version: MDB Free 4.4.5
 *
 *
 * Copyright: Material Design for Bootstrap
 * https://mdbootstrap.com/
 *
 * Read the license: https://mdbootstrap.com/license/
 *
 *
 * Documentation: https://mdbootstrap.com/
 *
 * Getting started: https://mdbootstrap.com/getting-started/
 *
 * Tutorials: https://mdbootstrap.com/bootstrap-tutorial/
 *
 * Templates: https://'
forced  
False
mode    
'file'
new_filepath    
'CACHE/css/cf136be60f95.css'
self    
<compressor.css.CssCompressor object at 0x7fbe4aadf240>
compressor/base.py in handle_output at line 310
    def handle_output(self, mode, content, forced, basename=None):
        # Then check for the appropriate output method and call it
        output_func = getattr(self, "output_%s" % mode, None)
        if callable(output_func):
            return output_func(mode, content, forced, basename)
        # Total failure, raise a general exception
        raise CompressorError(
            "Couldn't find output method for mode '%s'" % mode)
    def output_file(self, mode, content, forced=False, basename=None):
basename    
None
content 
'/*!
 * Material Design for Bootstrap 4
 * Version: MDB Free 4.4.5
 *
 *
 * Copyright: Material Design for Bootstrap
 * https://mdbootstrap.com/
 *
 * Read the license: https://mdbootstrap.com/license/
 *
 *
 * Documentation: https://mdbootstrap.com/
 *
 * Getting started: https://mdbootstrap.com/getting-started/
 *
 * Tutorials: https://mdbootstrap.com/bootstrap-tutorial/
 *
 * Templates: https://'
forced  
False
mode    
'file'
output_func 
<bound method Compressor.output_file of <compressor.css.CssCompressor object at 0x7fbe4aadf240>>
self    
<compressor.css.CssCompressor object at 0x7fbe4aadf240>
compressor/base.py in output at line 302
        if not output:
            return ''
        if settings.COMPRESS_ENABLED or forced:
            filtered_output = self.filter_output(output)
            return self.handle_output(mode, filtered_output, forced)
        return output
    def handle_output(self, mode, content, forced, basename=None):
        # Then check for the appropriate output method and call it
filtered_output 
'/*!
 * Material Design for Bootstrap 4
 * Version: MDB Free 4.4.5
 *
 *
 * Copyright: Material Design for Bootstrap
 * https://mdbootstrap.com/
 *
 * Read the license: https://mdbootstrap.com/license/
 *
 *
 * Documentation: https://mdbootstrap.com/
 *
 * Getting started: https://mdbootstrap.com/getting-started/
 *
 * Tutorials: https://mdbootstrap.com/bootstrap-tutorial/
 *
 * Templates: https://'
forced  
False
mode    
'file'
output  
'/*!
 * Material Design for Bootstrap 4
 * Version: MDB Free 4.4.5
 *
 *
 * Copyright: Material Design for Bootstrap
 * https://mdbootstrap.com/
 *
 * Read the license: https://mdbootstrap.com/license/
 *
 *
 * Documentation: https://mdbootstrap.com/
 *
 * Getting started: https://mdbootstrap.com/getting-started/
 *
 * Tutorials: https://mdbootstrap.com/bootstrap-tutorial/
 *
 * Templates: https://'
self    
<compressor.css.CssCompressor object at 0x7fbe4aadf240>
compressor/css.py in output at line 51
                ret = []
                for media, subnode in self.media_nodes:
                    subnode.extra_context.update({'media': media})
                    ret.append(subnode.output(*args, **kwargs))
                return ''.join(ret)
        return super(CssCompressor, self).output(*args, **kwargs)
__class__   
<class 'compressor.css.CssCompressor'>
args    
[
'file'
]
kwargs  
{
'forced': False
}
self    
<compressor.css.CssCompressor object at 0x7fbe4aadf240>
compressor/css.py in output at line 49
                    ret.append(subnode.output(*args, **kwargs))
compressor/templatetags/compress.py in render_compressed at line 107
        rendered_output = compressor.output(mode, forced=forced)
compressor/templatetags/compress.py in render at line 131
        return self.render_compressed(context, self.kind, self.mode, forced=forced)
Called from: django/template/base.py in render_annotated

I have used django-cookiecuttter as the base template for my site. Only yesterday I read a separate issue raised against django-cookiecutter for another Internal Server Error issue which I hoped may help me too (even though the details appeared different), but I have tried removal of "min" from the css file without success.

As the error message mentions storage and compressor, is it possible that this is Django-compressor related or whitenoise (I have both installed)? I have looked into trying to compile offline looking the instructions here, but this might be out of date by now and as my site is working well locally I want to avoid unnecessary coding if I can help it. Assistance would be greatly appreciated.

I am using windows with Python 3.6.2 and Django 2.0.2. My production static settings are as follows:

# Static Assets
# ------------------------
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

# COMPRESSOR
# ------------------------------------------------------------------------------
COMPRESS_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
COMPRESS_URL = STATIC_URL
COMPRESS_ENABLED = env.bool('COMPRESS_ENABLED', default=True)

Thanks in advance.

UPDATE:

I still see the Internal Server Error, however, I'm sure this relates to the way I have set up my bucket. I have followed this tutorial adding the IAM group and policy, but I must be doing something wrong because I get an improperly configured error message with the following details:

Client error:An error occurred (403) when calling the HeadBucket operation: Forbidden

My policy in AWS is as follows (of which I have tried a few iterations of):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:ListAllMyBuckets",
                "s3:HeadBucket",
                "s3:ListObjects"
            ],
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::mybucket/*",
                "arn:aws:s3:::mybucket"
            ]
        }
    ]
}

I'm quickly running out of hair as I seem to be pulling it out at an alarming rate. No doubt this is yet another schoolboy error, so appreciate your time in reviewing.

  • start by setting `DEBUG=False`. That should give you a better message so you work out what is wrong. If may be as simple as needing to set HOSTS in `settings.py` – HenryM Feb 24 '18 at 15:59
  • Thank you Henry, I will bare this in mid for future questions, I can see so many messages and settings, that it is hard to know which ones are the most appropriate / useful :) – K. Benneworth Feb 25 '18 at 14:09

2 Answers2

0

The error message says that you have an invalid AWS S3 bucket name: Invalid bucket name "". An empty name is invalid.

In cookiecutter-django, it's defined by this setting.

You need to create a S3 bucket in AWS and set the environment variable DJANGO_AWS_STORAGE_BUCKET_NAME on Heroku:

heroku config:set DJANGO_AWS_STORAGE_BUCKET_NAME='the-bucket-name'

EDIT:

I'm not sure how much cookiecutter-django is up to date with Whitenoise + django-compressor + Heroku, but there is an issue opened on django-compressor's repo that might be interesting.

Bruno A.
  • 1,765
  • 16
  • 17
  • Thank you Bruno. I had misinterpreted comments about the need to have this simply as a setting rather than actually creating AWS storage and setting it up. I have followed the following tutorial [link](https://www.caktusgroup.com/blog/2014/11/10/Using-Amazon-S3-to-store-your-Django-sites-static-and-media-files/), which has been very helpful, however, I am still getting an Internal Server Error on my Heroku site and seeing a [403] forbidden error in Sentry. I will update the main question with details. – K. Benneworth Feb 25 '18 at 14:13
  • The tutorial you point at is great, but the error you're getting seems to indicate something is wrong with permissions. I would suggest to go back and create a bucket without customising the policy: 1) Create a bucket, with public read access 2) Create a IAM group with full S3 access 3) Add a user to that group, generate AWS key and secret for that user 4) Use that key ID and secret in your app. You might want to ask a new question... – Bruno A. Feb 26 '18 at 14:36
0

In answer to my "Update" & second question. I went through the AWS tutorial again from start to finish and although I think I did exactly the same as before, this time it appears to have worked as I am now onto yet another Internal Server Error - oh joy. The only think I can think of that felt different was the assigning of the policy to the group, so possibly the way I did it before, I failed to link it.

I will continue to search for answers to this problem before bugging everyone again, but please don't be surprised to see me back soon...