Installation & Infrastructure
ExecStart=/srv/SecBoard/venv/bin/gunicorn ... SecBoard.wsgi:application
If you are running commands manually, activate the environment first:
source /srv/SecBoard/venv/bin/activate
Run collectstatic to populate the staticfiles/ directory that Nginx serves:
source /srv/SecBoard/venv/bin/activate
python manage.py collectstatic --noinput
Then verify the Nginx location /static/ block points to the correct
alias path and reload Nginx.
Use Certbot with the webroot method. First, deploy the HTTP-only Nginx config and confirm the domain resolves. Then:
sudo certbot certonly --webroot -w /srv/SecBoard/letsencrypt -d your-domain.com -d www.your-domain.com
Verify auto-renewal: sudo certbot renew --dry-run. Full steps in
SSL, Domain & Reverse Proxy.
csrf_trusted_origins in credential.py:
csrf_trusted_origins = [
'https://your-domain.com',
'https://www.your-domain.com',
]
Also ensure debug = False is set. Then restart the Gunicorn service.
Initial Configuration
- Set
debug = False,allowed_hosts, andcsrf_trusted_originsincredential.py. - Configure the site name, domain, and protocol in Admin → Site Settings.
- Set up at least one Mail Server and Mail Account for sending system emails.
- Create your Platform Roles and Access Groups.
- Create your administrator user and assign the superuser or appropriate admin group.
/secboard_admin/:
- App Conf → Site Settings — site name, domain, protocol, project type, default email.
- App Conf → Contact Settings — public contact info, social media links, email recipients for the contact form.
Work through this checklist:
- Confirm a Mail Server and Mail Account exist in Admin → App Conf.
- Check the SMTP host, port, and TLS settings — a common mistake is using port 587 with SSL instead of STARTTLS.
- Verify the mail account password is correct by saving it again (the field is encrypted).
- Check that the feature requiring email (invitations, risk reports, etc.) has a mail account assigned to it.
- Check Django logs at
/srv/SecBoard/logs/gunicorn_error.logfor SMTP exceptions.
Users, Roles & Access
Check in order:
- No password set? New accounts are created without a password. Send the user to
/password_reset/or use the First Login flow at/first_login/. - Account inactive? Open the user in Users → Users and check that Active is ticked, and that the Start Date is not in the future and End Date is not in the past.
- AD account disabled? If the user is AD-synced, check whether their Active Directory account has the
ACCOUNTDISABLEflag set. - 2FA required? If Require Two-Factor Authentication is enabled, the user must complete 2FA setup before they can proceed.
The user has no Access Groups, or their groups have no permissions enabled. Check:
- The user is assigned at least one Access Group (Users → Users → Edit → Access Groups).
- The group has the relevant module's view permission enabled.
- The group has Show link enabled for the module — this is a separate permission from view access and controls whether the module appears in the navigation menu.
- Uncheck Active (immediate effect), or
- Set an End Date in the past — the account becomes inactive at that point automatically.
- Password reset: Ask the user to go to
/password_reset/and enter their email — they will receive a one-time reset link (valid 1 hour). - First Login: Share the URL
/first_login/and the company cabinet password (set in Admin → Cabinet Settings). The user enters their email and cabinet password to receive a magic login link by email.
- First, ask the user to try their backup codes — they received 10 codes when they set up 2FA. One backup code can be used at the 2FA challenge screen.
- If all backup codes are lost, open the user in Users → Users → Edit, turn off Require Two-Factor Authentication, and save. This allows the user to log in without 2FA so they can set up a new authenticator device.
- After they set up a new device, re-enable the requirement if needed.
Active Directory & LDAP
- Email attribute missing: Check that
attr_emailis set to the correct AD attribute and that the user has a value for it. SecBoard uses the email as the username. - User object filter too restrictive: The default
(objectClass=user)should match standard AD users. If you customised the filter, verify it still matches the user. - Account disabled in AD: SecBoard mirrors the
ACCOUNTDISABLEflag — if the AD account is disabled, SecBoard will also disable the user. - Password contains special characters: Ensure the password field is not being URL-encoded or truncated before reaching the LDAP bind.
- Group matching is case-sensitive. The SecBoard
CabinetGroupname must exactly match the AD group CN (e.g.SecBoard-Risk-Managers, notsecboard-risk-managers). - Sync is additive only — groups are added but never removed. If a user has a group in SecBoard that isn't in AD, it stays.
- The user must log in again after you configure sync — the sync runs on login, not retroactively.
- Check that the SecBoard group is either global (no company set) or belongs to the same company as the user.
Email & Notifications
noreply@ and reports@
both using the company SMTP). Each feature in SecBoard can be assigned a different account.
- Check that the default mail account is configured in Admin → App Cabinet → Cabinet Settings for the user's company.
- Verify the SMTP credentials by saving the mail account again — the bind password field is encrypted and needs to be re-entered if blank.
- Check spam/junk folders on the recipient's side.
- Review
/srv/SecBoard/logs/gunicorn_error.logfor SMTP exception details. - Confirm the sender domain has valid SPF/DKIM records — major email providers reject unsigned mail.
- Confirm Auto-Reply Mail Account is set.
- Confirm Auto-Reply Subject and body are filled in.
- Confirm the contact form's Reply Email is set to a valid address.
Personal Account & Profile
- Format: JPEG or PNG (not WebP, GIF, or SVG)
- File size: under 2 MB
- Dimensions: at least 200 × 200 pixels
Common Errors
- Ensure
csrf_trusted_originsincredential.pyincludes your full domain with scheme (e.g.https://your-domain.com). - Restart Gunicorn after any
credential.pychange:sudo systemctl restart secboard. - Clear browser cookies for the domain — a stale CSRF cookie from a previous session can cause this.
allowed_hosts in credential.py. Add it:
allowed_hosts = ['your-domain.com', 'www.your-domain.com', '127.0.0.1']
Restart Gunicorn after the change.
This happens when SECURE_SSL_REDIRECT = True (set by debug = False)
but Django doesn't see the X-Forwarded-Proto: https header from Nginx.
proxy_set_header X-Forwarded-Proto $scheme;
settings.py already has SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
— the Nginx header is the missing piece.
sudo systemctl status secboard
sudo systemctl status SecBoard_celery
sudo systemctl status SecBoard_celery_beat
Celery requires Redis to be running (sudo systemctl status redis).
Check /srv/SecBoard/logs/celery_worker.log and
celery_beat.log for error details.
client_max_body_size is too low. The default SecBoard Nginx
config sets this to 100M. If you reduced it, restore it:
client_max_body_size 100M;
Reload Nginx after the change: sudo systemctl reload nginx.