Module Flags
Last updated
Feature-gate the panel’s major subsystems. When a module is off, the panel hides the corresponding pages and the require_module middleware short-circuits handler execution.
Flags
All on server_settings, boolean, default true on upgrades so nothing disappears silently:
| Field | Module |
|---|---|
dns_enabled | DNS zones + records |
mail_enabled | Mailboxes, forwarders, mail groups, deliverability, throttles |
security_enabled | CrowdSec, AppSec, AppArmor, Snuffleupagus surface |
quota_enabled | Package quotas and enforcement |
api_enabled | Public automation API |
postgres_enabled | PostgreSQL databases (pre-existing) |
Fresh installs seed the flags from the JABALI_MODULES environment variable at first boot — the migration only sets defaults for pre-existing rows.
API
PATCH /api/v1/admin/settings— set individual flags.GET /api/v1/admin/settings/modules/status— read current module state.POST /api/v1/admin/settings/modules/install— trigger the install-on-enable hook when flipping a module back on.
Behavior
- Panel navigation hides sections whose module is off.
- Handlers behind
require_modulereturn403 module_disabledwhen hit directly. - Enabling a module later runs its install-on-enable hook (e.g. bringing up services, seeding defaults).
Server settings — cache & registrar & DNS policy
Related admin knobs that ship alongside the module flags on the same settings page:
Nginx FastCGI cache (M46):
nginx_cache_max_size_gb(default4) — total shared cache size.nginx_cache_keyzone_mb(default64) — metadata zone size.nginx_cache_inactive_min(default60) — inactivity timeout.
Domain registrar expiry — domains.registrar_expires_at and domains.registrar_checked_at populated by the domain_expiry_ticker reconciler via WHOIS. Rendered in the DNS Zones list without hitting WHOIS per row. Failed lookups still stamp checked_at so the ticker doesn’t hammer-retry.
DNS user record policy — server_settings.dns_user_record_policy is a JSON matrix restricting which record types non-admin users can create / edit / delete on their own zones:
{
"A": {"create": true, "edit": true, "delete": true},
"AAAA": {"create": true, "edit": true, "delete": true},
"CNAME": {"create": true, "edit": true, "delete": true},
"MX": {"create": true, "edit": true, "delete": true},
"TXT": {"create": true, "edit": true, "delete": true},
"SRV": {"create": true, "edit": true, "delete": true},
"CAA": {"create": true, "edit": true, "delete": true}
}
Default is fully permissive to preserve current behavior. Presets are exposed in the UI so admins don’t hand-edit JSON.
Tenant nginx options — server_settings.tenant_domain_options_enabled (default off) lets domain owners set domains.nginx_safe_options (max body size, HSTS, security headers, gzip). Rendered from a safe template — no raw nginx directives, no proxy_pass, no ip_access (SSRF-safe by construction).
CrowdSec login allowlist
Auto-allowlist source IPs of successful panel + SSH logins so a normal admin logging in from home doesn’t get banned mid-session.
crowdsec_login_allowlist_enabled(default on) — master switch.crowdsec_login_allowlist_ttl_hours(default168= 7 days) — refreshed on every successful login.
Sync happens via security.crowdsec.login_allowlist.apply writing /etc/jabali-panel/login-allowlist.conf. See also CrowdSec Allowlists for manual entries.