Developer docs

Developers

Configuration reference

Every environment variable and command-line option.

Procera is configured in three places:

  1. The server: command-line options and PROCERA_* environment variables, read at start-up. These are for whoever runs the installation.
  2. The system console (/system): email delivery, quotas and platform floors, changed in the app by system administrators and recorded in the system audit log.
  3. Workspace Settings (Admin › Settings): everything about how one workspace works, changed by its owner and admins and recorded in its audit log.

See also: Install with Docker Compose and First-time setup.

1. Server options and environment variables

The procera binary has five commands:

CommandWhat it does
procera serveRuns the server. Add --all to run the API, the background worker (event dispatch, email sending) and the scheduler in one process. Without --all, only the API runs: nothing sends email or publishes scheduled versions. Use --all today.
procera migrateApplies database migrations. Run it as the procera_migrator role, never the app role.
procera keygenPrints a new random master key (base64) for PROCERA_MASTER_KEY on standard output.
procera rotate-master-keyMoves the database to a new master key. Stop the server, back up, run procera keygen for a new key, then run this with PROCERA_DATABASE_URL, the current PROCERA_MASTER_KEY and the new key in PROCERA_NEW_MASTER_KEY (or --new-key; the variable keeps it out of the process list). In one transaction it re-seals every value sealed under the master key (workspace keys, two-step secrets, invitation tokens, older email bodies), checks each with the new key, and prints the counts; it refuses a malformed key, the same key, or a current key that doesn't open the data. Then put the new key in .env as PROCERA_MASTER_KEY and start the server. Access tokens and signed file links issued before stop working (people stay signed in). Keep the old key with backups taken before the rotation.
procera healthcheckExits 0 if the server on PROCERA_BIND answers GET /healthz with 200, else 1 (loopback is used when bound to 0.0.0.0). For container health checks.

Every option can be given as a flag or as its environment variable; a flag wins. An empty variable counts as not set. Logs are JSON lines on standard error; standard output is reserved for command output.

procera serve

VariableFlagDefaultRequiredPurpose
PROCERA_BIND--bind127.0.0.1:8080 (the container image sets 0.0.0.0:8080)NoAddress and port the HTTP API listens on.
(none)--alloffYes, in practiceRun the worker and scheduler in the same process (see above).
PROCERA_DATABASE_URL--database-urlnoneYesPostgreSQL URL for the runtime role procera_app, e.g. postgres://procera_app:PASSWORD@db:5432/procera. Without it the server starts in a smoke-test mode with no accounts or data. The server refuses to start if any workspace table lacks forced row-level security.
PROCERA_MASTER_KEY--master-keynoneYes, with a database32 random bytes, base64 (procera keygen or openssl rand -base64 32). Root key for secrets at rest (workspace keys, stored files, two-step secrets, the saved SMTP password) and for token signing.
PROCERA_PUBLIC_URL--public-urlhttp://127.0.0.1:8080Yes, in practiceThe address people use in the browser. Used in email links and as the default passkey relying party. System › Email & platform shows the value in use and where it came from.
PROCERA_WEBAUTHN_RP_ID--webauthn-rp-idthe host of PROCERA_PUBLIC_URL (a loopback IP maps to localhost)NoPasskey relying-party id, a registrable domain such as example.com. Changing it later invalidates registered passkeys.
PROCERA_SMTP_URL--smtp-urlnoneNoSMTP relay, e.g. smtp://user:pass@host:587?tls=required (STARTTLS) or smtps://user:pass@host:465 (implicit TLS). Wins over the email settings saved in the system console. With neither, emails stay queued.
PROCERA_MAIL_FROM--mail-fromProcera <no-reply@localhost>With PROCERA_SMTP_URLSender used with PROCERA_SMTP_URL. Console settings carry their own sender.
PROCERA_CACHE_URL--cache-urlnone (in-process cache)NoValkey/Redis URL for caches and rate limits, e.g. redis://valkey:6379. The cache is advisory: if it's unreachable at start-up the server logs a warning and uses the in-process cache. Use a shared cache once you run more than one server process.
PROCERA_INSECURE_COOKIES--insecure-cookiesfalseNoUse non-Secure cookies without the __Host- prefix. Only for local HTTP development and tests.
PROCERA_LOGIN_RATE_PER_MIN--login-rate-per-min30NoSign-in attempts allowed per client IP per minute. Raise only for test environments where everyone shares one IP.
PROCERA_TRUSTED_PROXY_HOPS--trusted-proxy-hops1NoHow many reverse proxies in front of the server append to X-Forwarded-For. The client address is taken that many entries from the end, so earlier (client-supplied) entries are ignored. Use 0 if the server is reached directly with no proxy.
PROCERA_FILES_DIR(none)a procera-files folder in the system temp directory (the container image sets /var/lib/procera/files)Yes, in practiceWhere uploaded files are stored (encrypted). Without it, files can be lost on restart, and the console warns about it. Used when PROCERA_STORAGE is local (the default).
PROCERA_STORAGElocal—Nolocal keeps files on disk (PROCERA_FILES_DIR); s3 keeps them in an S3-compatible bucket (AWS S3, Ceph, SeaweedFS, Cloudflare R2…; checked against SeaweedFS). Files are encrypted before they leave the server either way. A wrong S3 setting stops the server at start-up rather than failing uploads later.
PROCERA_S3_BUCKET(none)—With s3The bucket.
PROCERA_S3_REGION(from the AWS environment)—OftenFor example eu-west-1.
PROCERA_S3_ENDPOINTAWS—For non-AWS storesFor example https://s3.example.com or http://seaweedfs:8333.
PROCERA_S3_ACCESS_KEY_ID / PROCERA_S3_SECRET_ACCESS_KEY(from the AWS environment or instance role)—Unless a role provides themKeys for the bucket. Keep them in your secret store.
PROCERA_S3_PATH_STYLEtrue—Noendpoint/bucket/key addressing, which most non-AWS stores need. Set false for virtual-hosted AWS buckets.
PROCERA_S3_ALLOW_HTTPfalse—NoPlain HTTP endpoints, for development or a private network only.
PROCERA_S3_PREFIX(none)—NoA folder inside the bucket, so several environments can share one bucket.
PROCERA_CLAMD_ADDR(none)noneRecommendedClamAV clamd address (host:port, e.g. clamav:3310). Without it, uploads are checked only for the EICAR test file.
PROCERA_EGRESS_ALLOW(none)noneOnly for internal receiversComma-separated address ranges (CIDR, e.g. 10.0.0.0/8,192.168.10.5/32) that webhooks and single sign-on providers may reach even though they are private. Without it, webhooks go only to public https addresses on ports 443, 80, 8443 or 8080; with it, the listed ranges also accept plain http and any port.
PROCERA_LOG(none)infoNoLog filter in tracing EnvFilter syntax, e.g. warn, debug, info,procera_notify=debug.

procera migrate

VariableFlagDefaultRequiredPurpose
PROCERA_MIGRATOR_URL--migrator-urlnoneYesPostgreSQL URL for the procera_migrator role.
PROCERA_LOG(none)infoNoAs above.

procera healthcheck

VariableFlagDefaultPurpose
PROCERA_BIND--bind127.0.0.1:8080Address of the running server to probe.

Database roles

Run deploy/sql/00-roles.sql once per database, as a superuser, before the first migration. It creates:

  • procera_migrator: owns the schema and runs migrations. Never used by the running server.
  • procera_app: the runtime role. Not an owner, no BYPASSRLS, data changes only, so row-level security always applies.
  • procera_discovery: cannot log in. Owns only a few cross-workspace lookup functions that return ids.

It also creates the citext and ltree extensions. Set the two login roles' passwords yourself (the Compose stack does this from deploy/.env).

Endpoints for monitoring

PathAnswers
GET /healthz{"status":"ok"} while the process is up.
GET /readyzstatus (ready or not_ready), database (ok, unavailable or none) and the cache backend and health. A degraded cache stays ready.
GET /versionName, version and server time.

Variables used by the Compose files only

deploy/compose.yml also reads these from deploy/.env. The server never sees them directly.

VariableDefaultPurpose
POSTGRES_PASSWORDnone (required)Postgres superuser password.
PROCERA_MIGRATOR_DB_PASSWORDnone (required)Password set for procera_migrator on first start; builds PROCERA_MIGRATOR_URL.
PROCERA_APP_DB_PASSWORDnone (required)Password set for procera_app on first start; builds PROCERA_DATABASE_URL.
PROCERA_HTTP_PORT8080Host port (optionally ip:port) for the web container's HTTP.
PROCERA_HTTPS_PORT8443Host port for HTTPS, used when PROCERA_SITE_ADDRESS is a domain.
PROCERA_SITE_ADDRESS:80Caddy site address. A domain name turns on automatic HTTPS certificates.
PROCERA_IMAGE, PROCERA_WEB_IMAGEprocera:local, procera-web:localImage names to build or use.
MAILPIT_UI_PORT8025Mailpit's web inbox, on 127.0.0.1 (with the mail profile).
COMPOSE_PROFILESnoneOptional services to start: cache, scan, mail.

2. Settings in the app

System console

System administrators sign in and open System console (from Choose a workspace, or /system). Two-step verification is required. Changes are recorded in System audit.

PageWhat you can change
WorkspacesCreate workspaces (New workspace: name, slug, configuration profile, owner email), Make read-only, Lock, Reactivate, Schedule deletion (with a grace period), and Edit quotas per workspace (member limit, storage limit).
Quotas & usageSeats and storage per workspace, and Defaults by profile: the member and storage limits copied into each new workspace. The member limit is enforced when people are invited.
Email & platformEmail delivery: SMTP host, port, Encryption, username, password, from address, sender name and reply-to, plus Send test email. Changes apply without a restart. If PROCERA_SMTP_URL is set, it wins and the form is replaced by a notice. Platform basics, File storage and malware scanning: shown as configured on the server, with where each value comes from.
Platform healthStatus checks for the installation.
System auditThe system-plane audit log.

Platform floors set the minimum every workspace must meet. A workspace can be stricter but never looser: a looser value is rejected when saved, and existing looser values are clamped and shown as Platform minimum in workspace Settings. Keys with floors today: auth.mfa.required_roles, auth.mfa.allowed_methods, auth.password.min_length, auth.password.breach_check, auth.session.idle_timeout, auth.session.absolute_timeout, auth.stepup.window, api.tokens.max_ttl, access.admin_content_access_log, retention.governance_record.keep_for, files.max_size, files.scan.required. There is no console page for floors yet: set them through the system API (GET /sysapi/v1/settings, PUT /sysapi/v1/settings/{key} with {"value": …, "reason": "…"}), signed in as a system administrator.

Workspace Settings

Workspace owners and admins open Admin › Settings. Each setting shows its effective value and where it comes from (default, profile, workspace, department or platform minimum). The categories:

CategoryCovers
General & brandingName, logo, colours, language, time zone and the words Procera uses
Sign-in & securityPasswords, two-step verification, session length and admin access logging. Single sign-on has its own page, Admin › Single sign-on (see below)
People & directoryWho can join, what happens when someone leaves, positions
Documents & reviewsWho must review before publishing, review cycles, numbering
Acknowledgements & announcementsWhen people must re-acknowledge, campaign reminders and escalation, announcement rules
NotificationsWhich channels Procera uses, digests and quiet hours
Data, retention & filesUpload limits, malware scanning, and how long records are kept
Single sign-on (OpenID Connect)

In Admin › Single sign-on, copy the redirect URL (<PROCERA_PUBLIC_URL>/api/v1/auth/sso/callback) into a new OpenID Connect web application at your provider (Okta, Microsoft Entra ID, Google Workspace, Keycloak and others), then enter its issuer URL, client ID, client secret and the email domains it vouches for. Procera checks the provider's /.well-known/openid-configuration before saving. Members whose verified email is in a trusted domain can then choose Sign in with SSO; they must already be members (invite them as usual). Require it turns off passwords for everyone except workspace owners, who keep password + two-step verification so a provider outage can't lock you out. A provider on a private network must be listed in PROCERA_EGRESS_ALLOW. Decisions and limits: docs/22 A-50.

Some settings can be overridden per department. The configuration profile chosen when the workspace was created only sets the starting values. The full catalogue is in docs/20.

3. Security notes

Reverse proxy and TLS

The procera server speaks plain HTTP and does not serve the web app. Put a reverse proxy in front that:

  • terminates TLS (HTTPS is required outside local trials; see cookies below);
  • serves the built web app (npm run build in web/ produces web/dist) and falls back to index.html for unknown paths, because the app uses browser history routing;
  • forwards /api/, /sysapi/, /healthz, /readyz and /version to the server, on the same origin as the web app;
  • replaces X-Forwarded-For with the real client address. Procera trusts the first address in that header for sign-in rate limits and audit records, so a proxy that appends to a client-supplied header lets clients pick their own address. Don't expose the server port directly.

The Compose stack's web container (Caddy) does all of this. If you run your own proxy, a minimal Caddy setup:

procera.example.com {
	encode zstd gzip
	@api path /api/* /sysapi/* /healthz /readyz /version
	handle @api {
		reverse_proxy 127.0.0.1:8080
	}
	handle {
		root * /srv/procera/web/dist
		try_files {path} /index.html
		file_server
	}
}

Caddy gets the certificate automatically, and it replaces client-sent X-Forwarded-For unless you configure trusted_proxies.

A minimal nginx setup (certificates from your usual tooling):

server {
    listen 443 ssl;
    http2 on;
    server_name procera.example.com;
    ssl_certificate     /etc/ssl/procera/fullchain.pem;
    ssl_certificate_key /etc/ssl/procera/privkey.pem;

    root /srv/procera/web/dist;
    location ~ ^/(api|sysapi)/ {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;   # replace, don't append
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    location ~ ^/(healthz|readyz|version)$ {
        proxy_pass http://127.0.0.1:8080;
    }
    location / {
        try_files $uri /index.html;
    }
}

server {
    listen 80;
    server_name procera.example.com;
    return 301 https://$host$request_uri;
}

Set PROCERA_PUBLIC_URL=https://procera.example.com to match.

Cookies and sessions

  • The refresh cookie is HttpOnly, SameSite=Strict, Secure and named with the __Host- prefix, so browsers send it only over HTTPS, only to the exact host, and never on cross-site requests. Cookie endpoints also require a custom request header, which blocks cross-site form posts.
  • PROCERA_INSECURE_COOKIES=true drops Secure and the prefix so a plain-HTTP setup works. Use it only for local development and tests.
  • Session length, idle timeout and the step-up window are workspace settings (Sign-in & security), bounded by platform floors.

Master key

  • Generate it with procera keygen, store it in a secret manager, and back it up apart from database backups. Losing it makes the encrypted data unreadable: workspace keys, stored files, two-step secrets and the saved SMTP password.
  • Don't change it on an existing installation: there is no root-key rotation command yet. Each workspace's key can be rotated with Rotate key under Admin › Encryption.
  • External key management (KMS/HSM) is designed but not built yet; the key is read from the environment.

SMTP TLS modes

WhereModeSetting
System consoleSTARTTLS (required)Upgrades to TLS and stops delivery if the server doesn't offer it. Usually port 587. Recommended.
System consoleImplicit TLSTLS from the first byte. Usually port 465.
System consoleNoneUnencrypted. Accepted only when the host is localhost, 127.0.0.1 or ::1 (a relay on the same machine).
PROCERA_SMTP_URLsmtp://…:587?tls=requiredSTARTTLS required.
PROCERA_SMTP_URLsmtps://…:465Implicit TLS.
PROCERA_SMTP_URLsmtp://host:port with no tls parameterUnencrypted, with no host restriction. Use only for a test inbox such as Mailpit or a relay on a private network.

The saved SMTP password is encrypted under the system key and never shown again. A password in PROCERA_SMTP_URL lives wherever your environment is stored, so protect that file.

Other hardening

  • The container image runs as a non-root user on a distroless base (no shell).
  • Keep Postgres off the public network. The Compose stack publishes only the web container.
  • Turn on ClamAV (PROCERA_CLAMD_ADDR) before people upload files.
  • Keep /readyz internal if you don't want its database and cache status visible; the bundled Caddyfile forwards it.

Source: docs/guides/configuration.md