Works when DEBUG=True, but not if DEBUG=False #256

Closed
opened 2025-12-29 16:20:13 +01:00 by adam · 14 comments
Owner

Originally created by @joachimtingvold on GitHub (Jul 20, 2016).

Hi,

Without having done any troubleshooting or deep-dive in the code, I think I'm experiencing a weird issue.

Trying to get Netbox up and running on Debian Jessie. Installing from git/source (master-branch), and all of the prerequisites and database and whatnot is set up to work as they should.

Where my configuration differs from the examples, is how the WSGI-part is done. In stead of running it through gunicorn (and having nginx/apache reverseproxying), I've configured the app to be run directly through apache via mod_wsgi.

The "weird" part is that I get Bad Request (400), but if I set DEBUG = True, it works.

Originally created by @joachimtingvold on GitHub (Jul 20, 2016). Hi, Without having done any troubleshooting or deep-dive in the code, I think I'm experiencing a weird issue. Trying to get Netbox up and running on Debian Jessie. Installing from git/source (master-branch), and all of the prerequisites and database and whatnot is set up to work as they should. Where my configuration differs from the examples, is how the WSGI-part is done. In stead of running it through gunicorn (and having nginx/apache reverseproxying), I've configured the app to be run directly through apache via mod_wsgi. The "weird" part is that I get `Bad Request (400)`, but if I set `DEBUG = True`, it works.
adam closed this issue 2025-12-29 16:20:13 +01:00
Author
Owner

@joachimtingvold commented on GitHub (Jul 20, 2016):

Vhost-config in Apache;

<VirtualHost *:3004>
    ServerName ipam.foo.bar
    ServerAdmin webmaster@foo.bar

    SSLEngine On
    SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
    SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

    ErrorLog /var/log/apache2/error-ipam.foo.bar.log
    CustomLog /var/log/apache2/access-ipam.foo.bar.log combined

    DocumentRoot /srv/vhosts/ipam.foo.bar/

    # static files
    Alias /static /srv/vhosts/ipam.foo.bar/netbox/static
    <Directory "/srv/vhosts/ipam.foo.bar/netbox/static">
        Options +Indexes +FollowSymLinks +MultiViews
        AllowOverride None
        Require all granted
        SSLRequireSSL
    </Directory>

    # WSGI-stuff
    WSGIDaemonProcess netbox user=www-data group=www-data threads=5
    WSGIScriptAlias / /srv/vhosts/ipam.foo.bar/app-netbox.wsgi

    <Directory "/srv/vhosts/ipam.foo.bar/">
        WSGIProcessGroup netbox
        WSGIApplicationGroup %{GLOBAL}

        AllowOverride None
        Options +ExecCGI +FollowSymLinks
        SSLRequireSSL
        AllowOverride None      
        Require all granted
    </Directory>
</VirtualHost>

Content of app-netbox.wsgi;

"""
WSGI config for do_ipam project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
"""

import os
import sys
from django.core.wsgi import get_wsgi_application
sys.path.insert(0, '/srv/vhosts/ipam.foo.bar/netbox')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "netbox.settings")

application = get_wsgi_application()
@joachimtingvold commented on GitHub (Jul 20, 2016): Vhost-config in Apache; ``` <VirtualHost *:3004> ServerName ipam.foo.bar ServerAdmin webmaster@foo.bar SSLEngine On SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key ErrorLog /var/log/apache2/error-ipam.foo.bar.log CustomLog /var/log/apache2/access-ipam.foo.bar.log combined DocumentRoot /srv/vhosts/ipam.foo.bar/ # static files Alias /static /srv/vhosts/ipam.foo.bar/netbox/static <Directory "/srv/vhosts/ipam.foo.bar/netbox/static"> Options +Indexes +FollowSymLinks +MultiViews AllowOverride None Require all granted SSLRequireSSL </Directory> # WSGI-stuff WSGIDaemonProcess netbox user=www-data group=www-data threads=5 WSGIScriptAlias / /srv/vhosts/ipam.foo.bar/app-netbox.wsgi <Directory "/srv/vhosts/ipam.foo.bar/"> WSGIProcessGroup netbox WSGIApplicationGroup %{GLOBAL} AllowOverride None Options +ExecCGI +FollowSymLinks SSLRequireSSL AllowOverride None Require all granted </Directory> </VirtualHost> ``` Content of app-netbox.wsgi; ``` """ WSGI config for do_ipam project. It exposes the WSGI callable as a module-level variable named ``application``. For more information on this file, see https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/ """ import os import sys from django.core.wsgi import get_wsgi_application sys.path.insert(0, '/srv/vhosts/ipam.foo.bar/netbox') os.environ.setdefault("DJANGO_SETTINGS_MODULE", "netbox.settings") application = get_wsgi_application() ```
Author
Owner

@jeremystretch commented on GitHub (Jul 20, 2016):

Check that you've defined ALLOWED_HOSTS correctly in configuration.py.

@jeremystretch commented on GitHub (Jul 20, 2016): Check that you've defined `ALLOWED_HOSTS` correctly in `configuration.py`.
Author
Owner

@joachimtingvold commented on GitHub (Jul 20, 2016):

I've got the FQDN of the host itself, and the FQDN of the host that does reverseproxy before it. Not sure how the ALLOWED_HOSTS is supposed to work in that matter? The host that does reverseproxy is nginx, and it's sets the headers with the real IP of the client;

                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Find it a bit weird that it works with DEBUG = True, as I can't find anything that should "bypass" the ALLOWED_HOSTS if it's set to True (i.e. the only line of code that actually uses the DEBUG parameter, is logger.setLevel(logging.DEBUG)).

@joachimtingvold commented on GitHub (Jul 20, 2016): I've got the FQDN of the host itself, and the FQDN of the host that does reverseproxy before it. Not sure how the `ALLOWED_HOSTS` is supposed to work in that matter? The host that does reverseproxy is nginx, and it's sets the headers with the real IP of the client; ``` proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; ``` Find it a bit weird that it works with `DEBUG = True`, as I can't find anything that should "bypass" the `ALLOWED_HOSTS` if it's set to `True` (i.e. the only line of code that actually uses the `DEBUG` parameter, is `logger.setLevel(logging.DEBUG)`).
Author
Owner

@jeremystretch commented on GitHub (Jul 20, 2016):

Try setting

DEBUG = False
ALLOWED_HOSTS = ['*']

Find it a bit weird that it works with DEBUG = True, as I can't find anything that should "bypass" the ALLOWED_HOSTS if it's set to True

The DEBUG is a core Django setting with wide-ranging impact beyond how it's used in the NetBox source.

@jeremystretch commented on GitHub (Jul 20, 2016): Try setting ``` DEBUG = False ALLOWED_HOSTS = ['*'] ``` > Find it a bit weird that it works with DEBUG = True, as I can't find anything that should "bypass" the ALLOWED_HOSTS if it's set to True The `DEBUG` is a core Django setting with wide-ranging impact beyond how it's used in the NetBox source.
Author
Owner

@joachimtingvold commented on GitHub (Jul 21, 2016):

That works.

How is the ALLOWED_HOSTS supposed to work?

INTERNET -> Reverseproxy (NGINX) --> Netbox / WSGI (Apache2)

As mentioned, the ALLOWED_HOSTS was set to the FQDN of both the reverseproxy, and the Netbox/Apache2. The IPv6 address in the access logs on Apache2 is the one from the reverseproxy, which I've double-checked that resolves from the FQDN provided.

In either case, the ALLOWED_HOSTS is just for "unsafe" requests, like POST, so viewing the site normally (read-only, which is default without logging in), should work fine regardless of the hosts set in ALLOWED_HOSTS?

@joachimtingvold commented on GitHub (Jul 21, 2016): That works. How is the `ALLOWED_HOSTS` supposed to work? ``` INTERNET -> Reverseproxy (NGINX) --> Netbox / WSGI (Apache2) ``` As mentioned, the `ALLOWED_HOSTS` was set to the FQDN of both the reverseproxy, and the Netbox/Apache2. The IPv6 address in the access logs on Apache2 is the one from the reverseproxy, which I've double-checked that resolves from the FQDN provided. In either case, the `ALLOWED_HOSTS` is just for "unsafe" requests, like `POST`, so viewing the site normally (read-only, which is default without logging in), should work fine regardless of the hosts set in `ALLOWED_HOSTS`?
Author
Owner

@wanglf commented on GitHub (Jul 21, 2016):

netbox version: 1.3.0

I encounter the same problem on CentOS 7.2.1511 even if I set

DEBUG = False
ALLOWED_HOSTS = '[*]'

Bad Request (400) Returned.

@wanglf commented on GitHub (Jul 21, 2016): netbox version: 1.3.0 I encounter the same problem on CentOS 7.2.1511 even if I set ``` DEBUG = False ALLOWED_HOSTS = '[*]' ``` Bad Request (400) Returned.
Author
Owner

@jeremystretch commented on GitHub (Jul 21, 2016):

ALLOWED_HOSTS is a list of hostnames to which the service will respond. HTTP requests listing any other hostnames will be rejected. It needs to match whatever hostname should be received by the WSGI service. See the Django documentation for more detail.

@jeremystretch commented on GitHub (Jul 21, 2016): `ALLOWED_HOSTS` is a list of hostnames to which the service will respond. HTTP requests listing any other hostnames will be rejected. It needs to match whatever hostname should be received by the WSGI service. See the [Django documentation](https://docs.djangoproject.com/en/1.9/ref/settings/#allowed-hosts) for more detail.
Author
Owner

@joachimtingvold commented on GitHub (Jul 21, 2016):

INTERNET -> web1.foo.bar (reverseproxy) --> netbox1.foo.bar (Netbox/WSGI)
ALLOWED_HOSTS = ['netbox1.foo.bar', 'web1.foo.bar']
root@netbox1:~# dig web1.foo.bar aaaa +short
fc00:10::10

Requesting a page from the Internet, hitting web1.foo.bar on IPv4, this is the Apache2 log on netbox1.foo.bar;

fc00:10::10 - - [21/Jul/2016:13:45:27 +0000] "GET / HTTP/1.0" 400 396 "https://netbox.foo.bar/login/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"

... which yields the Bad Request (400) page.

@joachimtingvold commented on GitHub (Jul 21, 2016): ``` INTERNET -> web1.foo.bar (reverseproxy) --> netbox1.foo.bar (Netbox/WSGI) ``` ``` ALLOWED_HOSTS = ['netbox1.foo.bar', 'web1.foo.bar'] ``` ``` root@netbox1:~# dig web1.foo.bar aaaa +short fc00:10::10 ``` Requesting a page from the Internet, hitting web1.foo.bar on IPv4, this is the Apache2 log on netbox1.foo.bar; ``` fc00:10::10 - - [21/Jul/2016:13:45:27 +0000] "GET / HTTP/1.0" 400 396 "https://netbox.foo.bar/login/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36" ``` ... which yields the `Bad Request (400)` page.
Author
Owner

@joachimtingvold commented on GitHub (Jul 21, 2016):

The documentation for ALLOWED_HOSTS says this;

When DEBUG is True or when running tests, host validation is disabled; any host will be accepted. Thus it’s usually only necessary to set it in production.

... which explains why it works when DEBUG = True. It does not, however, explain the issue I see above. As far as I can see, that configuration should work.

@joachimtingvold commented on GitHub (Jul 21, 2016): The documentation for `ALLOWED_HOSTS` says this; > When DEBUG is True or when running tests, host validation is disabled; any host will be accepted. Thus it’s usually only necessary to set it in production. ... which explains why it works when `DEBUG = True`. It does not, however, explain the issue I see above. As far as I can see, that configuration should work.
Author
Owner

@joachimtingvold commented on GitHub (Jul 21, 2016):

... and now I see the culprit. netbox/netbox/settings.py has USE_X_FORWARDED_HOST = True, which means it's the client IPv4 address that's used to validate, and not web1.foo.bar (since we set that header on the reverseproxy/web1.foo.bar).

@joachimtingvold commented on GitHub (Jul 21, 2016): ... and now I see the culprit. `netbox/netbox/settings.py` has `USE_X_FORWARDED_HOST = True`, which means it's the client IPv4 address that's used to validate, and not web1.foo.bar (since we set that header on the reverseproxy/web1.foo.bar).
Author
Owner

@joachimtingvold commented on GitHub (Jul 21, 2016):

Not sure if configuration.py overrides settings.py, but even when setting USE_X_FORWARDED_HOST = False in both those files, I still get the Bad Request (400) page.

@joachimtingvold commented on GitHub (Jul 21, 2016): Not sure if `configuration.py` overrides `settings.py`, but even when setting `USE_X_FORWARDED_HOST = False` in both those files, I still get the `Bad Request (400)` page.
Author
Owner

@jeremystretch commented on GitHub (Jul 21, 2016):

Your log seems to indicate that you're using netbox.foo.bar as the hostname, but you have

ALLOWED_HOSTS = ['netbox1.foo.bar', 'web1.foo.bar']

Does it work when you add netbox.foo.bar?

@jeremystretch commented on GitHub (Jul 21, 2016): Your log seems to indicate that you're using `netbox.foo.bar` as the hostname, but you have ``` ALLOWED_HOSTS = ['netbox1.foo.bar', 'web1.foo.bar'] ``` Does it work when you add `netbox.foo.bar`?
Author
Owner

@joachimtingvold commented on GitHub (Jul 21, 2016):

It's not like it's a big deal, however, but I still find it strange that it doesn't work.

@joachimtingvold commented on GitHub (Jul 21, 2016): It's not like it's a big deal, however, but I still find it strange that it doesn't work.
Author
Owner

@joachimtingvold commented on GitHub (Jul 21, 2016):

Yes, that works, @jeremystretch. And that explains -- I thought the ALLOWED_HOSTS was what host the clients used, and not the host used to actually reach that page.

Not sure if brainfart, or if instructions are unclear. But thanks (-:

@joachimtingvold commented on GitHub (Jul 21, 2016): Yes, that works, @jeremystretch. And that explains -- I thought the `ALLOWED_HOSTS` was what host the clients used, and not the host used to actually reach that page. Not sure if brainfart, or if instructions are unclear. But thanks (-:
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#256