Help & Support warning Other

Common Errors & Troubleshooting

Back to manual
Systematic troubleshooting reference: log file locations, HTTP error codes (400/403/404/413/500/502/504), authentication failures, AD/LDAP issues, email/SMTP errors, Celery task failures, database errors, and a 10-point quick diagnostics checklist.

Log File Locations

LogPathWhat it contains
Gunicorn errors/srv/SecBoard/logs/gunicorn_error.logPython tracebacks, SMTP errors, unhandled exceptions
Gunicorn access/srv/SecBoard/logs/gunicorn_access.logEvery HTTP request: status code, response time, IP
Celery worker/srv/SecBoard/logs/celery_worker.logBackground task execution, failures, retries
Celery beat/srv/SecBoard/logs/celery_beat.logScheduled task triggering
Nginx errors/var/log/nginx/error.logUpstream connection failures, TLS errors, config errors
Nginx access/var/log/nginx/access.logAll requests reaching Nginx (before proxying)
systemd journaljournalctl -u secboard -n 100Service start/stop events, crash restarts

The fastest way to see recent errors: tail -f /srv/SecBoard/logs/gunicorn_error.log while reproducing the problem in the browser.

HTTP Errors

400Bad Request — CSRF verification failed

Cause: Django's CSRF middleware rejected the request because the origin is not in CSRF_TRUSTED_ORIGINS, or because a stale/missing CSRF cookie was submitted.

Fix:

  1. Add your domain to csrf_trusted_origins in credential.py with the full scheme:
    csrf_trusted_origins = ['https://your-domain.com']
  2. Restart Gunicorn: sudo systemctl restart secboard
  3. If the error persists for one specific browser, clear cookies for the domain and try again.
400Bad Request — "Invalid HTTP_HOST header"

Cause: The request Host header is not in Django's ALLOWED_HOSTS.

Fix: Add the domain to allowed_hosts in credential.py:

allowed_hosts = ['your-domain.com', 'www.your-domain.com', '127.0.0.1']
Restart Gunicorn after the change.

403Forbidden — Access Denied inside the application

Cause: The user's Access Groups do not include the required permission for the action or section.

Fix: Open Users → Groups, find the user's group, and enable the required permission. Check the Show link permission separately — it controls navigation visibility independently of content access.

404Not Found — Static or media files

Cause: collectstatic was not run, or the Nginx alias path is wrong.

Fix:

  1. Run: python manage.py collectstatic --noinput
  2. Verify the Nginx config alias matches STATIC_ROOT (/srv/SecBoard/staticfiles/) and MEDIA_ROOT (/srv/SecBoard/media/).
  3. Reload Nginx: sudo systemctl reload nginx
413Request Entity Too Large

Cause: Nginx's client_max_body_size is lower than the uploaded file size.

Fix: Set client_max_body_size 100M; in the Nginx server block and reload:

sudo systemctl reload nginx

500Internal Server Error

Cause: An unhandled Python exception in the application. The browser receives a generic error page while the real traceback is in the Gunicorn error log.

Diagnostic:

tail -50 /srv/SecBoard/logs/gunicorn_error.log

Look for the last Traceback (most recent call last) block. Common causes:

  • Database connection error — MySQL/MariaDB is down or credentials changed. Check credential.py database settings.
  • Missing migration — a new model was deployed without running python manage.py migrate.
  • Import error — a Python package is missing. Run pip install -r requirements.txt inside the virtualenv.
502Bad Gateway — Nginx cannot reach Gunicorn

Cause: Gunicorn is not running, or the proxy_pass port in the Nginx config does not match the --bind port in the Gunicorn service file.

Diagnostic:

sudo systemctl status secboard
journalctl -u secboard -n 30

Fix:

  1. If the service is stopped: sudo systemctl start secboard
  2. If it keeps crashing, check gunicorn_error.log for the startup error.
  3. Verify proxy_pass http://127.0.0.1:PORT; in Nginx matches the --bind 127.0.0.1:PORT in the service file.
504Gateway Timeout

Cause: A request took longer than proxy_read_timeout (60 s default in the Nginx config) or the Gunicorn --timeout (120 s).

Fix options:

  • Increase proxy_read_timeout in Nginx if the operation legitimately takes longer (e.g. large report generation).
  • Move long-running tasks to Celery background workers instead of synchronous request handling.
  • Check if a slow database query is the root cause — look for slow query warnings in MySQL logs.
Infinite Redirect — HTTP keeps redirecting to HTTPS

Cause: SECURE_SSL_REDIRECT = True (enabled by debug = False) but Django doesn't see the X-Forwarded-Proto: https header that Nginx should send. Django thinks the request is HTTP and redirects again.

Fix: Ensure the Nginx location / block includes:

proxy_set_header X-Forwarded-Proto $scheme;
settings.py already trusts this header via SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https').

Authentication Problems

User cannot log in — "Invalid email or password"

Work through this checklist in order:

CheckHow to verifyFix
No password setUser was created without a password (new accounts have no password by default)Send user to /password_reset/ or use First Login flow at /first_login/
Account inactiveUsers → user profile: check Active status, Start/End datesTick Active, adjust dates, or clear end date
AD account disabledCheck AD: userAccountControl flagRe-enable in Active Directory; SecBoard mirrors the flag on next login
Brute-force lockoutMultiple rapid failed attempts from one IP trigger a lockout periodWait for the lockout to expire, or clear the lockout via the admin panel
Email typoCheck exact email used vs email in Users listCorrect the email in the user profile
Password reset email not received
  1. Check spam / junk folder first.
  2. Verify a Mail Account is configured for password reset emails (Admin → App Cabinet → Cabinet Settings → Mail Account).
  3. Check gunicorn_error.log for SMTPException or ConnectionRefusedError immediately after the reset request.
  4. Verify the sender domain has valid SPF and DKIM records — many providers silently reject mail without them.
  5. Confirm the user's email address in SecBoard exactly matches what they typed (no leading/trailing spaces).
2FA code is always invalid
  1. Clock skew: TOTP codes are time-based. If the server clock differs from the user's device by more than 30 seconds, codes will be rejected. Sync the server clock: sudo timedatectl set-ntp true.
  2. Wrong account in app: The user may have re-scanned a QR code for a different service. Ask them to delete the SecBoard entry from their authenticator and re-enrol.
  3. Admin reset: Open the user in Users → Edit, disable Require Two-Factor Authentication, let the user log in, and re-set up 2FA from their Personal Cabinet.
AD / LDAP login fails despite correct credentials

Check in order:

  1. Use the Test Connection button on the AD connection in the admin panel to confirm the service account bind works.
  2. Check gunicorn_error.log for ldap3 exceptions (search for LDAPException or ldap3).
  3. Verify attr_email is correct and the user has a non-empty value for that attribute in AD.
  4. Verify the user is within the base_dn / user_search_ou scope.
  5. Check that ldap3 is installed in the virtualenv: /srv/SecBoard/venv/bin/pip show ldap3
  6. If LDAPS is enabled, confirm the DC certificate's common name or SAN matches the server_url. SecBoard accepts self-signed certs, but the server URL must be reachable on port 636.

Email & Notification Errors

No emails sent at all from the platform

Diagnostic sequence:

  1. Trigger a password reset and immediately check gunicorn_error.log for an SMTP exception.
  2. Common errors and fixes:
    Error in logCauseFix
    ConnectionRefusedErrorSMTP host or port is wrong, or port is blocked by firewallVerify host/port; test with telnet smtp.host.com 587
    SMTPAuthenticationErrorWrong username or passwordRe-enter the mail account password in Admin → Mail Accounts
    SMTPServerDisconnectedWrong TLS setting (SSL on STARTTLS port or vice versa)Use port 587 with STARTTLS or port 465 with SSL — not mixed
    ssl.SSLCertVerificationErrorSelf-signed or expired cert on SMTP serverEnable "Allow self-signed" on the Mail Server if supported, or use a valid cert
Some notification types are sent but others are not

Each feature in SecBoard can be assigned a different Mail Account. Check that the specific feature has a mail account assigned:

  • Password reset / First Login: Admin → App Cabinet → Cabinet Settings → Mail Account (per company)
  • Contact form auto-reply: Admin → App Conf → Contact Settings → Auto-Reply Mail Account
  • Risk reports: Admin → App Risk → Risk Report Email Config → Mail Account
  • Access request notifications: Admin → App Access → Email Notification Config → Mail Account
  • Incident / GDPR / password recovery emails: use the default mail account from Django settings

Celery & Background Tasks

Scheduled tasks not running (reports not generated, notifications not sent on schedule)

Step 1 — Check all three services:

sudo systemctl status secboard
sudo systemctl status SecBoard_celery
sudo systemctl status SecBoard_celery_beat

All three must be active (running). If any is stopped or failed:

sudo systemctl start SecBoard_celery
sudo systemctl start SecBoard_celery_beat

Step 2 — Check Redis:

sudo systemctl status redis
redis-cli ping   # should return PONG

Step 3 — Check task logs:

tail -50 /srv/SecBoard/logs/celery_worker.log
tail -50 /srv/SecBoard/logs/celery_beat.log
Celery worker crashes immediately on start

Common causes (visible in celery_worker.log or journalctl -u SecBoard_celery -n 50):

  • Database unreachable: check MySQL/MariaDB status and credential.py database settings.
  • Missing module: activate the virtualenv and run pip install -r requirements.txt.
  • Redis not available: Celery cannot connect to its broker. Ensure Redis is running and the host/port in settings matches.

Database Errors

"django.db.OperationalError: (2003) Can't connect to MySQL server"
  1. Check MySQL/MariaDB is running: sudo systemctl status mysql
  2. Verify the database host, port, name, user, and password in credential.py.
  3. Test connectivity: mysql -h HOST -u USER -p -D DBNAME
  4. If using a remote DB, check that the SecBoard server IP is allowed to connect (MySQL GRANT statements or firewall rules).
"Table 'db.app_foo' doesn't exist" / "no such column"

Cause: New migrations were not applied after deploying an update.

Fix:

source /srv/SecBoard/venv/bin/activate
python manage.py migrate

Then restart Gunicorn: sudo systemctl restart secboard

"Incorrect string value" / charset errors

Cause: The database or table is not using utf8mb4 charset, which is required for emoji and full Unicode support.

Fix: Ensure the database was created with:

CREATE DATABASE secboard CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Also verify credential.py includes 'OPTIONS': {'charset': 'utf8mb4'} in the database settings.

Permission & Access Errors

User sees a blank dashboard / no modules in the navigation menu
  1. Go to Users → Users → [user] → Edit. Confirm the user has at least one Access Group.
  2. Open Users → Groups → [group]. For each module the user should see:
    • Enable the module's View permission.
    • Enable the module's Show link permission — without this the module does not appear in the nav even if the user can access its content.
  3. Changes take effect immediately on the user's next page request (no restart needed).
Administrator can't access "Users" section — getting "Access Denied"

The Users section is protected by the User Management permission set. Even administrators need at least View Users enabled in their Access Group — unless they are a superuser.

Fix: Grant the group the relevant User Management permissions, or set is_superuser = True for the account in the Django admin panel (/secboard_admin/auth/user/).

File upload returns "Permission denied" in the logs

Cause: The operating system user running Gunicorn does not have write permission to the media/ directory.

Fix: The service file specifies ReadWritePaths=/srv/SecBoard/media. Ensure the directory is owned by the same OS user:

sudo chown -R cursor:cursor /srv/SecBoard/media
sudo chmod -R 755 /srv/SecBoard/media
Replace cursor with the actual user in your SecBoard_prod.service file.

After an Update / Redeploy

After pulling a new version of SecBoard, run this sequence to avoid most post-deploy errors:

source /srv/SecBoard/venv/bin/activate

# Install any new Python dependencies
pip install -r requirements.txt

# Apply database migrations
python manage.py migrate

# Rebuild static files
python manage.py collectstatic --noinput

# Restart the app and workers
sudo systemctl restart secboard
sudo systemctl restart SecBoard_celery
sudo systemctl restart SecBoard_celery_beat

# Reload Nginx (if config changed)
sudo nginx -t && sudo systemctl reload nginx

If the site shows a 500 error immediately after restarting, check gunicorn_error.log — a missing migration or a new required setting in credential.py are the most common causes.

Quick Diagnostics Checklist

When something breaks and you're not sure where to start:

#CheckCommand / location
1Is Gunicorn running?sudo systemctl status secboard
2Is Nginx running?sudo systemctl status nginx
3Is MySQL/MariaDB running?sudo systemctl status mysql
4Is Redis running?sudo systemctl status redis
5Any Python exceptions?tail -50 /srv/SecBoard/logs/gunicorn_error.log
6Any Nginx errors?tail -20 /var/log/nginx/error.log
7Are migrations applied?python manage.py showmigrations | grep "\[ \]"
8Is debug = False set correctly?credential.py
9Does the domain appear in allowed_hosts?credential.py
10Is disk space available?df -h /srv/SecBoard

Attachments

No attachments for this article.