Customizing and Debugging OpenStack Horizon with AI
Horizon is the dashboard your users actually see. Here is how I customize it, debug the blank-page failures, and use AI to navigate its Django internals safely.
- #openstack
- #horizon
- #dashboard
- #django
- #devops
Operators love the OpenStack CLI. Users love the dashboard. And when OpenStack Horizon breaks, you do not get a stack trace in the browser — you get a blank white page, an Apache 500, or a login screen that loops forever, while every user on the cloud assumes the entire platform is down. Horizon is “just a Django app,” but it is a Django app wired into Keystone, theming, and a pile of plugin dashboards, and debugging it means knowing where each of those seams can fail.
I am a backend operator, not a frontend specialist, so Horizon is exactly the area where an AI assistant pulls its weight: it knows Django conventions cold, it can read a traceback faster than I can, and it drafts theme overrides without me memorizing Horizon’s settings layout. As always, it is a fast junior engineer — I let it propose, I confirm against my actual files, and it never touches the running cloud.
Where Horizon Actually Lives
Before debugging anything, know the moving parts. Horizon runs under a WSGI server (Apache mod_wsgi or uWSGI), reads local_settings.py for configuration, and talks to Keystone for auth. A blank page almost always means a Python exception that the web server swallowed.
The first command is not an openstack command — it is checking that the API endpoints Horizon depends on are healthy:
openstack endpoint list
openstack token issue
If token issue fails, Horizon’s login loop is a Keystone problem, not a Horizon problem. This distinction has saved me hours, and it is the first thing I tell the AI when I describe a symptom — ground the model in which layer is actually broken.
Reading the Traceback
Horizon logs to the web server’s error log. The Django traceback there is your real diagnostic:
sudo tail -100 /var/log/apache2/error.log
I paste that traceback into a session with Claude and ask: “Which Horizon setting or plugin is causing this ImportError?” Django tracebacks are long and the relevant line is usually buried; the model reliably points at the broken import or the misconfigured OPENSTACK_HOST. That is genuine time saved — reading Django stack traces is tedious, mechanical work.
When a Horizon outage affects users, I log the whole investigation in my incident response dashboard so the next blank-page panic has a precedent to follow.
Customizing the Theme
Most Horizon customization is a custom theme plus a few local_settings.py overrides. A minimal theme override:
# in local_settings.py
DEFAULT_THEME = 'mytheme'
AVAILABLE_THEMES = [
('default', 'Default', 'themes/default'),
('mytheme', 'My Theme', 'themes/mytheme'),
]
After changing settings or static assets you must recompress and collect static files, then restart the web server:
python manage.py collectstatic --noinput
python manage.py compress --force
I have the AI draft theme overrides — SCSS variables, logo swaps, the settings block — because I do not do this often enough to remember the structure. Then I diff its output against my real local_settings.py before applying. A model is happy to invent a setting name that does not exist, so the diff-and-verify step is mandatory.
Pro Tip: After any Horizon settings or static change, restart the web server and hard-refresh with cache disabled. A huge fraction of “my theme change did not work” reports are stale collectstatic output or browser caching, not a real config problem — rule those out before you debug anything deeper.
Enabling and Disabling Dashboards
Horizon’s panels are pluggable via enabled-files. To toggle a dashboard you add or edit a file in the enabled/ directory and restart. When a third-party dashboard plugin breaks the whole UI — which happens — the fix is often disabling one panel by setting DISABLED = True in its enabled-file. I ask AI to identify which enabled-file corresponds to the panel in the traceback; it maps the Python module name to the file faster than I can grep for it.
Session and Cookie Failures
The most maddening Horizon bug is the one where login appears to work but immediately bounces you back, or where the dashboard logs you out every few minutes. This is almost always a session backend problem — Horizon defaults to signed cookies for sessions, which breaks once a user accumulates enough scoped tokens to overflow the cookie size limit. The fix is moving sessions to memcached or a database:
# in local_settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
CACHES = {'default': {'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'LOCATION': '127.0.0.1:11211'}}
I have the AI draft this block — it knows the Django session backends cold — and then I confirm memcached is actually running and reachable before applying it. This is a textbook example of the division of labor: the model produces correct, idiomatic Django config in seconds, but it has no idea whether your memcached is up. That verification is mine. Skipping it just trades one login loop for another, so I check the cache backend is live before I trust the fix.
The Performance Angle
Slow Horizon is usually slow API calls underneath, not slow Django. If a page hangs, time the underlying API directly:
openstack --debug server list
The --debug flag shows each REST call and its timing. If server list is slow on the CLI, Horizon’s instances page will be slow too, and the fix is in Nova or Placement, not Horizon. I feed the debug timing to the AI to spot which call dominates.
Guardrails
Horizon configuration changes can lock every user out of the cloud at once, so even though it is “just a dashboard,” the blast radius is your entire user base. My rules:
- The AI drafts settings, themes, and enabled-files; it never edits the live
local_settings.pyor restarts the production web server itself. - I test config changes on a staging Horizon, or at minimum keep a known-good
local_settings.pybackup I can restore in one command. - Before applying any AI-suggested setting, I confirm it exists in the Horizon docs — invented setting names are the model’s favorite failure mode here.
Because Horizon work is real code, I also run theme and plugin changes through my code review dashboard before they ship. My vetted prompts live in the prompt workspace, reusable templates are in the OpenStack prompt pack, and for editing the Python and SCSS files I lean on Cursor.
The Takeaway
Horizon failures look scary because they are silent and they affect everyone, but underneath they are ordinary Django problems with an OpenStack accent. An AI assistant that knows Django turns the blank page into a readable traceback and the theming guesswork into reviewable diffs. Keep it in the junior-engineer lane, test on staging, and your dashboard stops being the thing that makes the whole cloud look down.
The mindset shift that helped me most was to stop treating Horizon as an OpenStack mystery and start treating it as a Django app I happen to run. Once you do that, every tool and instinct from the wider Django world applies — the logs are in the obvious place, the settings follow normal conventions, and an AI assistant fluent in Django becomes immediately useful. The OpenStack-specific parts are a thin layer on top, and they are exactly the parts worth grounding the model in with your real endpoint list before you trust a single suggestion.
Need a hand untangling a Horizon plugin mess or building a branded theme? Work with me, or keep exploring the OpenStack guides and the prompt library.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.