ozpanel sovereign hosting
Get ozpanel

Operator & API reference

Security

Generated firewall, tenant network policy, CrowdSec, SSH, secrets, logins, sessions, audit, signed releases.

Layers

LayerMechanism
Node firewallnftables from service declarations; default drop
Tenant networkOutbound policy matched by uid
AbuseKernel flood limits + CrowdSec, bans shared
People3 roles, Argon2id, TOTP, CSRF, scoped tokens
NodesCluster CA, mutual TLS, route allowlist
SecretsAES-256-GCM, reveals audited
ChangeAppend-only audit log, signed releases

Firewall

Each module declares port, protocol, scope. The ruleset (inet ozpanel_fw) is derived. Scopes: public · peers · admin (management sources; open while none) · local.

CallDoes
GET /nftables/plan, /nftables/enforcementImplied ruleset; per port: listening, reach, as declared
GET/POST/DELETE /nftables/admin-sourcesManagement sources; scope all | console; says if you are covered
GET /nftables/audit, POST {content}Lockout and exposure check
POST /nftables/baseline/apply, /nftables/applyApply; 20 s auto-revert unless POST /nftables/confirm {token}
POST /nftables/persist, /reload, PUT /nftables/peersPersist; reload; resync peer sets
Flood limit (/nftables/settings)Default
conn_per_ip_smtp20
conn_per_ip_mail_clients100
syn_per_ip_per_sec100
icmp_echo_per_sec20
admin_console_restrictedfalse

Ports

ScopePorts
public80, 443 tcp+udp, 53, 25, 587, 465, 143, 993, 110, 995
admin22, 9600
peers9601, 656, 3306 (+ container bridge), 4567, 4568, 4444, 4569, 5432, 6379, 26379, 26380, 3901
local6432, 2019, 8081, 8080, 6060, 11332–11334, 10025, 10041, 4190, 24, 20000, 11211, 3900, 3903, 7680–7699
retired (closed)24007 and bricks, 55555/udp (GlusterFS)
Operator · Firewall. — ozpanel screenshot
Operator · Firewall.

Tenant network policy

Table inet ozpanel_tenants, matched on socket uid; reject, not drop. Plan value, tenant override.

FieldDefault
outbound_defaultallow
deny_ports25, 465, 587
deny_cidrs169.254/16, 10/8, 172.16/12, 192.168/16, 100.64/10
allow_ports, allow_cidrsempty (used when default is deny)
listen_portsempty

Guard: every non-public declared port closed to all tenant uids, except 3306, 6432, 6379, 10025. /network-policy, …/tenants/{id}, …/plans/{id}, POST …/apply. /proc mounted hidepid=invisible.

CrowdSec

Engine, local API and firewall bouncer per node; decisions in PostgreSQL, shared. Bans stay in the kernel if the database is down. Hub auto-upgrade off.

Setting (/crowdsec/settings)Default
smtp_auth_fail_count / _window_min5 / 10
silent_conn_count / _window_min10 / 10
ban_base_hours / ban_max_hours4 (doubles) / 168
trusted_login_hours24
Rule auto-upgradeoff
log_level, log_media, compress_logs, prometheus_*info, file, true, full

Never banned: management sources, cluster nodes, recent successful logins. GET /crowdsec/decisions · POST …/decisions/add {"ip","duration","reason"} · …/delete.

SSH

GET/PUT /ssh/settings; drop-in, sshd -t, reload; sessions kept.

KeyDefault
port (per node)22
permitrootloginyes (install and join use it)
passwordauthentication, pubkeyauthenticationyes, yes
maxauthtries, logingracetime6, 120
x11forwarding, allowtcpforwardingyes, yes
clientaliveinterval, clientalivecountmax0, 3

Restrict with management sources first, confirm keys, then tighten.

Secrets

  • Storespanel_secrets (replicated, AES-256-GCM under app_key) · /etc/ozpanel/secrets/ files.
  • CallsGET/POST /secrets, GET/DELETE /secrets/{name}, GET /secrets/files, POST /secrets/files/{name}/reveal (audited).
  • App keyPOST /secrets/app-key/rotate: secret store on this node. Cluster-wide coordinated rotation: not available.
  • Cluster secretsPUT /cluster/secrets/{name}, …/rollout, POST /cluster/secrets/pull. Service rotations: Redis ACL, PgBouncer, MariaDB, webmail DB.
Operator · Secrets. — ozpanel screenshot
Operator · Secrets.

Logins and sessions

ItemValue
Password hashArgon2id, 64 MiB, 3 iterations, parallelism 2
Minimum length10
Lockout5 failures → 15 min; 20 per IP per 15 min → 429
2FATOTP, optional; 10 single-use recovery codes
Sessionozpanel_session, HttpOnly, SameSite=Lax; 12 h sliding (mailbox 30 days); CSRF header
Reset / invite1 h / 7 days, single use; 3 per address per hour
Admin restrictionadmin_console_restricted: super_admin sessions and tokens only from management sources. Break-glass: ozpanel admin console-restriction off.
Recovery token/etc/ozpanel/secrets/recovery_token; recovery routes only
Recovery grantsozpanel admin recovery-grant --node N --allow diagnose|recover|force

API tokens: see API · Tokens.

Audit log

Every mutating call, refusals and sign-ins: principal, role, tenant_id, module, action, params (≤1 MiB, unredacted), ok, ip, node. Append-only. GET /ozpanel/audit?module=&action=&principal=&since=&until= · /ozpanel/audit/export (HMAC-SHA256 signed).

Cluster key and releases

  • CA key/etc/ozpanel/pki/cluster-ca.key, 0600. On the master only. A successor that takes over becomes primary, not a CA holder; if the master is gone for good, import the CA on another node by hand. Never on shared storage.
  • SignsNode certs (ECDSA P-256, 90 days), declarations, releases.
  • ReleasesSignature verified before staging; unsigned refused. Members cannot fan out.
  • Node channel9601, mTLS, explicit route allowlist, fingerprint checked every call.
  • EvictionCerts revoked everywhere. Rotate cluster secrets after a hostile removal.

OS upgrades

os_auto_upgrades (/hosttune/settings): off by default; on = Debian unattended security upgrades daily. The panel itself: signed releases only.

Previous: Tenants, plans and files Next: API and automation