Error raised sending activation email

Hi, I recently enabled admin email notification of errors in the log configuration for my Django application. I’m using SendGrid as the email client. The email notification is working fine, and I’m noticing an error that I hadn’t seen before. It occurs whenever someone submits a registration form, triggering a confirmation email to be sent to that user.

The emails are being sent, but an error similar to this gets logged and emailed to me each time.

[Django] ERROR (EXTERNAL IP): Invalid HTTP_HOST header: '/run/gunicorn.sock:'. The domain name provided is not valid according to RFC 1034/1035.
webmaster@ifbt.farm <webmaster@ifbt.farm>	Fri, Oct 6, 2023 at 5:49 AM
To: dowdrake@gmail.com
Invalid HTTP_HOST header: '/run/gunicorn.sock:'. The domain name provided is not valid according to RFC 1034/1035.

DisallowedHost at /
Invalid HTTP_HOST header: '/run/gunicorn.sock:'. The domain name provided is not valid according to RFC 1034/1035.

Request Method: GET
Request URL: http://url1111.ifbt.farm/ls/click?upn=Rn6uuY2iv1LW59HkWR83rs-2FUAPMrXw42Fzv13-2B1epfz0XUod7LQRyej8P-2BvvoI9-2Bwntc_mEWvXA1o-2FLV9uv02p4M3WSr3lnvTv987Ro1g-2FVuuHiszF6FMD4WbmImEtUNPAY4WM9K3uWvzVpIS8EDSTn1puyxdC0aa4xpOH3PFwTfjrG3D106w1uFWdSod091gCifuZvjy22T-2FJjvUwubBDpG9KUqE-2B8eaA5CYNMUt4uU9Yq55kFUA742915OJ4D47eC6zhotlfDNPAXYEXKabNlUxjw-3D-3D
Django Version: 4.2.5
Python Version: 3.11.4

So the error is raised by the fact that the HOST_HEADER is invalid, but I’m not sure where that header is getting set. I assume it’s set somewhere in the Django code.
The subdomain url1111.ifbt.farm is one of the CNAME records that SendGrid specified to add to my DNS records.

My view passes the request and user to the form code, which sends the email via user.email_user()
The view is:

class RegistrationView(CreateView):
    form_class = RegistrationForm
    template_name = 'account/register.html'
    success_url = reverse_lazy('check_email')

    def form_valid(self, form):
        to_return = super().form_valid(form)

        user = form.save()
        user.is_active = False  # Turns the user status to inactive
        user.save()

        form.send_activation_email(self.request, user)

        return to_return

and the form is

class RegistrationForm(UserCreationForm):
    
    email = forms.EmailField(
        max_length=254, help_text='Enter a valid email address')
    
    class Meta:
        model = user_model
        fields = [
            'username',
            'email',
            'password1',
            'password2',
        ]
        
    def send_activation_email(self, request, user):
        current_site = get_current_site(request)
        subject = 'Activate Your Account'
        message = render_to_string(
            'account/activate_account.html',
            {
                'user': user,
                'domain': current_site.domain,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                'token': token_generator.make_token(user),
            }
        )   

        user.email_user(subject, message, html_message=message)

In my settings, I have

ALLOWED_HOSTS = ['ifbt.farm', 'www.ifbt.farm']

EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'apikey'
EMAIL_HOST_PASSWORD = SENDGRID_API_KEY

Thanks!
Dow

Hey, are you using Nginx as a web server or docker-compose? So, that I would tell you the possible way to sort it out.

I checked your view, the issue is not coming from there btw.

Thanks @Blaise-93!

Yes, I’m using Nginx and reverse proxy to Gunicorn.

Here’s my Nginx site configuration:

server {
    server_name ifbt.farm www.ifbt.farm;
    location = /favicon.ico { access_log off; log_not_found off; }
    location /static {
        alias /home/dow/ifbtdir/staticfiles;
    }
    # Deny illegal Host headers https://stackoverflow.com/questions/15238506/
    if ($host !~* ^(ifbt.farm|www.ifbt.farm)$ ) {
	    return 444;
    }
    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/ifbt.farm/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/ifbt.farm/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
    # deny all subdomains other than www (allowed above)
    server_name _;
    return 444;
}
server {
    if ($host = www.ifbt.farm) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    if ($host = ifbt.farm) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    listen 80;
    server_name ifbt.farm www.ifbt.farm;
    return 404; # managed by Certbot
}

I didn’t think it could be an issue with the Nginx config because I’m pretty sure the request is generated internally. Gunicorn/Django should never see an external request for http://url1111.ifbt.farm because it’s getting blocked by that second server block. You can click that link and see. You should get 444 because the server_name url1111.ifbt.farm is not allowed.

Hey Drake;
You forgot to add headers at the location in your nginx proxy-params setup.

Thus, the issue is that nginx is passing the host’s name as is. You can update the host header like this:

location / {
        proxy_set_header Host $host; // Add this to the code, buddy.
        include proxy_params;

        proxy_pass http://unix:/run/gunicorn.sock;
    }
Kindly make those changes.

PS: When HTTP Host is missing, $host will take on the value of the server_name directive, and it doesn’t go in accordance with RFC 1034/1035 guidelines, thus the error.
Goodluck!

Thanks @Blaise-93 – I didn’t know how the host header was getting set. I edited the Nginx config just how you said, but it didn’t quite work. It seems like it doubled up the host name so if I browse to any application url, I get this error from Django:

Exception Type: DisallowedHost at /farmyear/71
Exception Value: Invalid HTTP_HOST header: 'www.ifbt.farm,www.ifbt.farm'. The domain name provided is not valid according to RFC 1034/1035.
Raised during: main.views.FarmYearDetailView

That’s weird. May we see a detailed error log message of this recent error.

Pls ensure that the IP address and website matches correctly in your ALLOWED_HOSTset up.

You can read up this:

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header

Add this up also just below the other codes for reverse proxy for nginx to site the IP header which I think you included in your settings.py

nginx```
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme

Pardon my typos, I’m using my phone to type. :frowning:

I removed this condition from my Nginx configuration:

    # Deny illegal Host headers https://stackoverflow.com/questions/15238506/
    if ($host !~* ^(ifbt.farm|www.ifbt.farm)$ ) {
	    return 444;
    }

Now I’m not getting errors when users click the confirmation link any more, but I’m seeing lots of errors from garbage requests like this:

Invalid HTTP_HOST header: '147.182.224.162'. You may need to add '147.182.224.162' to ALLOWED_HOSTS.

DisallowedHost at /remote/login
Invalid HTTP_HOST header: '147.182.224.162'. You may need to add '147.182.224.162' to ALLOWED_HOSTS.

which was the reason I added that condition in the first place. I added back that conditon, but explicitly allowing the host “header” run/gunicorn.sock:

    # Deny illegal Host headers https://stackoverflow.com/questions/15238506/
    if ($host !~* ^(ifbt.farm|www.ifbt.farm|/run/gunicorn.sock:)$ ) {
            return 444;
    }

That seems to have solved my problem. I’m not getting errors on email confirmation link clicks anymore, the site is working fine, and headers like ‘147.182.224.162’ are getting filtered by Nginx again.

This is the error I got:

Invalid HTTP_HOST header: 'www.ifbt.farm,www.ifbt.farm'. The domain name provided is not valid according to RFC 1034/1035.

DisallowedHost at /dashboard/71
Invalid HTTP_HOST header: 'www.ifbt.farm,www.ifbt.farm'. The domain name provided is not valid according to RFC 1034/1035.

Request Method: GET
Request URL: http://url1111.ifbt.farm/ls/click?upn=Rn6uuY2iv1LW59HkWR83ro2McC2DWbMlop13hh695UAvo6qnfoYjVFVJLNjNm0-2FLkBMtiut8S4joBu7Rrv7W7g-3D-3D_FfL_mEWvXA1o-2FLV9uv02p4M3WSr3lnvTv987Ro1g-2FVuuHisjlUK4MwzBrCQWghwqpUp9WgF-2BHxNWX4NGVlknA-2BV9cqLGtU-2BJh8RVuapamAfE-2FX2KXFOVW8auNCxAIcT5DYczf4Iiqcxp2mGUJBgoJ2ZE4wf5nB7-2FojVa9vgDs3BbaGh-2BiwtIGh3R3dy-2BxQaaW6h9mfdJb4lwa6zD9wZZXn6fSQ-3D-3D
Django Version: 4.2.5
Python Version: 3.11.4

@Blaise-93 - Thanks for your help on this – I really appreciate it! But since everything seems to be working correctly after I modified the host filter, I think I’ll leave it as is without the last set of proxy_set_header directives you suggested.

1 Like

I’m glad I could be of help. I’m simply just giving back to community, because we started as a beginner some years back, and someone ones help us to locate or solve our problem. :smiley:
Perhap you might try to read the nginx headers set up link I sent to you, it could be of help someday to you.

Sounds good – will do! Thanks again.