Django Debug Toolbar is a fantastic tool for understanding what’s happening under the hood of your Django application, but running it in production is a security risk. Here’s how to enable it only when you need it, without leaving it accessible to the world.
How to Use Django Debug Toolbar Without Exposing It in Production
The core problem is that Django Debug Toolbar reveals sensitive information about your application’s internals, including database queries, settings, and request/response details. If exposed in production, this information can be a goldmine for attackers.
Here’s how to tame it:
1. Restrict Access by IP Address
This is the most common and effective method. You configure Django Debug Toolbar to only show up if the request comes from a specific IP address (or a range of addresses) that you control.
-
Diagnosis: Check your
settings.pyforDEBUG_TOOLBAR_CONFIG. -
Configuration: In your
settings.py:DEBUG = True # Keep DEBUG as True for local development ALLOWED_HOSTS = ['localhost', '127.0.0.1', '.your_production_domain.com'] # Ensure your production domain is here INTERNAL_IPS = ['127.0.0.1'] # Or your office/VPN IP address DEBUG_TOOLBAR_CONFIG = { 'INTERCEPT_REDIRECTS': False, 'SHOW_TOOLBAR_CALLBACK': 'debug_toolbar.panels.Toolbar.is_valid_request', 'RENDER_PANELS': True, 'ENABLE_STACKTRACES': True, 'RESULTS_CACHE_SIZE': 500, 'ENABLE_DUPLICATE_SUPERSESSION': True, 'SHOW_COLLAPSED': True, 'SQL_WARNING_THRESHOLD': 100, # milliseconds }If you’re deploying to a server, you’ll need to find your server’s public IP or use a VPN. If your server is on AWS, for example, you might use its public IP. If you’re accessing it from your office, it would be your office’s static IP.
-
Why it works: The
INTERNAL_IPSsetting tells Django Debug Toolbar which IP addresses are considered "internal" and therefore allowed to see the toolbar. When a request comes in, the toolbar checks if the request’s IP address is in this list. If it is, the toolbar is rendered.
2. Use a Custom SHOW_TOOLBAR_CALLBACK
For more granular control, you can write a custom Python function that determines whether to show the toolbar. This can involve checking user groups, specific request headers, or even a temporary flag.
-
Diagnosis: You’d look for a custom callback function defined in your
DEBUG_TOOLBAR_CONFIG. -
Configuration: In
settings.py:# ... other settings ... # Define a custom callback function in a file like your_app/utils.py # def my_custom_show_toolbar_callback(request): # # Example: Only show if user is logged in and is a superuser # return request.user.is_authenticated and request.user.is_superuser # Or, more securely, check a specific header set by a proxy/VPN # def my_custom_show_toolbar_callback(request): # return request.META.get('HTTP_X_SHOULD_SHOW_DEBUG_TOOLBAR') == 'true' DEBUG_TOOLBAR_CONFIG = { 'SHOW_TOOLBAR_CALLBACK': 'your_app.utils.my_custom_show_toolbar_callback', # ... other config ... }You would then need to ensure that the condition in your callback is met when you want to see the toolbar. For the header example, you’d need to configure your proxy (like Nginx or a load balancer) to add that header when you access the site.
-
Why it works: This callback function is executed for every request. If it returns
True, the toolbar is shown. If it returnsFalse, it’s suppressed. This gives you complete programmatic control over when the toolbar appears.
3. Conditional Loading Based on Environment Variables
You can use environment variables to control whether Django Debug Toolbar is enabled, ensuring it’s only active in your development or staging environments.
-
Diagnosis: Check your
settings.pyfor logic that reads environment variables. -
Configuration: In
settings.py:import os DEBUG = os.environ.get('DJANGO_DEBUG', 'False') == 'True' if DEBUG: # Only add debug_toolbar to INSTALLED_APPS and MIDDLEWARE if DEBUG is True INSTALLED_APPS = [ # ... other apps ... 'debug_toolbar', ] MIDDLEWARE = [ 'debug_toolbar.middleware.DebugToolbarMiddleware', # ... other middleware ... ] # You might also conditionally set INTERNAL_IPS or other configs INTERNAL_IPS = ['127.0.0.1'] # Or your dev machine's IP else: # Ensure debug_toolbar is NOT loaded in production INSTALLED_APPS = [ # ... other apps ... ] MIDDLEWARE = [ # ... other middleware ... ]When deploying, you would set
DJANGO_DEBUG=False(or omit it, as it defaults toFalse). Locally, you’d setDJANGO_DEBUG=True. -
Why it works: This approach leverages the standard
DEBUGsetting in Django. By makingDEBUGitself conditional on an environment variable, you ensure that thedebug_toolbarapp and middleware are only ever loaded whenDEBUGisTrue. This is a robust way to prevent it from being accidentally enabled.
4. Use a Separate Production settings.py or Overrides
Maintain distinct settings files for development and production. This is a best practice for managing configurations.
-
Diagnosis: Look for multiple
settings.pyfiles (e.g.,settings/base.py,settings/dev.py,settings/prod.py) or a mechanism for overriding settings. -
Configuration: If you use a structure like
manage.pyloadingmyproject.settings.prod, yoursettings/prod.pywould simply not include'debug_toolbar'inINSTALLED_APPSor the middleware.Alternatively, if you use a single
settings.pywith environment variable overrides:# settings.py import os DEBUG = os.environ.get('DJANGO_DEBUG', 'False') == 'True' INTERNAL_IPS = os.environ.get('DJANGO_INTERNAL_IPS', '127.0.0.1').split(',') INSTALLED_APPS = [ # ... ] MIDDLEWARE = [ # ... ] if DEBUG: INSTALLED_APPS += ['debug_toolbar'] MIDDLEWARE.insert(0, 'debug_toolbar.middleware.DebugToolbarMiddleware') # Insert at the beginning DEBUG_TOOLBAR_CONFIG = { 'INTERNAL_IPS': INTERNAL_IPS, # ... other configs ... }Then, when running locally:
DJANGO_DEBUG=True DJANGO_INTERNAL_IPS=127.0.0.1 python manage.py runserverAnd in production:
DJANGO_DEBUG=False python manage.py runserver -
Why it works: By ensuring that the
debug_toolbarapp and middleware are explicitly excluded from your production settings, you guarantee it cannot be loaded or run. This is the most foolproof method.
5. Local Development Server vs. Production Deployment
The simplest, yet often overlooked, solution is to never deploy your Django application with DEBUG = True. Django Debug Toolbar relies on DEBUG = True to function. If DEBUG is False in production, the toolbar won’t be active anyway.
-
Diagnosis: Check the value of
DEBUGin your production deployment environment. -
Configuration: In your production deployment script or configuration:
# Example for a Gunicorn deployment gunicorn myproject.wsgi:application --bind 0.0.0.0:8000 --workers 3 --env DJANGO_DEBUG=FalseOr ensure your
settings/prod.pyhasDEBUG = False. -
Why it works: The Django Debug Toolbar’s middleware and app registration are typically conditional on
DEBUGbeingTrue. WhenDEBUGisFalse, the toolbar is effectively disabled at a fundamental level, preventing it from ever being rendered or causing issues.
When you’ve successfully configured Django Debug Toolbar to only appear for your internal IPs, you’ll see the familiar toolbar appear on the right side of your browser window when accessing your site from an allowed IP. If you try from a different IP, it will be completely absent.
The next challenge you’ll likely face is optimizing your database queries, which Django Debug Toolbar will help you identify.