Skip to content

Configuration reference ​

How configuration works ​

Settings live in docker/.env.example, copied to .env next to the compose file. The compose file reads from .env and passes the values to services as environment variables. Some settings reach services under a different name, for example, STACK_NETWORK_SUBNET arrives at the API as RateLimit__KnownNetworks__0.

Not every setting lives in .env.example. A few rate-limit and order-numbering settings are set directly on the API service in a compose override file (see Reverse proxy and trusted proxies and API and ports for the complete list).

Compose files ​

Each compose file is for a different deployment target. Settings tables below show which tier each setting belongs to.

How a value reaches the API ​

The same setting can live in different places depending on whether it is in .env.example or set in a compose override. Here is an example using the trusted proxy and order settings:

bash
# Most settings live here:
RATE_LIMIT_TRUSTED_PROXY_COUNT=1
STACK_NETWORK_SUBNET=172.30.0.0/24
yaml
# Settings not in .env are set directly on the service:
services:
  hostpanel-api:
    environment:
      Orders__NumberPrefix: "ORD-"
      Orders__NumberDigits: 4
text
# .env variable                   → API configuration key
STACK_NETWORK_SUBNET              → RateLimit__KnownNetworks__0
RATE_LIMIT_TRUSTED_PROXY_COUNT    → RateLimit__TrustedProxyCount
Orders__NumberPrefix (override)   → Orders__NumberPrefix (no rename)
FilePurposeTier
docker-compose.hub.ymlStandalone self-host, used by install.shhub
docker-compose.shared.yml + docker-compose.dev.ymlLocal developmentdev
docker-compose.prod.ymlDeployment built from sourceprod
docker-compose.demo.ymlDemo stackdemo
docker-compose.platform.ymlJoining an existing networkn/a

Required secrets ​

Every CHANGE_ME is a placeholder, not a real default. The API refuses to start outside Development if a secret contains a placeholder or is too short. Always generate fresh values for production.
Generate secure random values using openssl:
  • JWT_SECRET (at least 32 characters): openssl rand -hex 32
  • ENCRYPTION_KEY (exactly 32 bytes, base64): openssl rand -base64 32
  • SESSION_ENCRYPTION_KEY (exactly 32 bytes, base64): openssl rand -base64 32
  • HOSTPANEL_BACKCHANNEL_LOGOUT_KEY (at least 16 characters): openssl rand -hex 24
  • POSTGRES_PASSWORD: openssl rand -hex 24
  • RABBITMQ_PASSWORD: openssl rand -hex 24

General ​

A server left on Development runs the DevDataSeeder and re-seeds test data on every restart. Always set ASPNETCORE_ENVIRONMENT=Production on a deployed host.
NameTypeDefaultDescription
ASPNETCORE_ENVIRONMENTstringDevelopmentRuntime mode: Production or Development. Development also runs DevDataSeeder, which re-seeds test data on every restart. A server must use Production. Required in hub and prod. Tiers: hub, prod, dev.
AUTH_APP_NAMEstringhostpanelApplication name registered with the auth layer (cookie and client naming). Tiers: hub, prod, dev.
DISABLE_RELEASE_UPDATE_CHECKSflagfalseSet to true to disable the daily check for a newer release on GitHub. Disable when the installation has no outbound internet access. Maps to ScheduledJobs__DisableReleaseUpdateChecks. Tiers: hub, prod.

Sign-in modes ​

Hostpanel supports two authentication modes: local (users managed by Hostpanel itself) and SSO (users signed in through an external OpenID Connect provider).

NameTypeDefaultDescription
AUTH_MODEstringlocallocal: Hostpanel authenticates its own users. sso: sign-in goes to an external OpenID Connect provider. Required. Tiers: all.

SSO settings ​

SSO These settings are required only when AUTH_MODE=sso.
NameTypeDefaultDescription
SSO_URLstringhttps://sso.example.comServer-to-server address the API reaches the provider at. Required for SSO. Tiers: all.
SSO_PUBLIC_URLstringhttps://sso.example.comWhere the browser is sent to sign in (provider's public hostname, issuer). Required for SSO. Tiers: all.
SSO_CLIENT_IDstringhostpanelClient identifier registered at the provider. Required for SSO. Tiers: all.
SSO_CALLBACK_URLstringhttps://panel.example.com/api/portal/auth/sso/callbackURL the provider redirects to after sign-in. The admin callback is <admin origin>/api/auth/callback. Required for SSO. Tiers: all.
SSO_SERVICE_KEYsecretCHANGE_MEMachine credential for reading the user directory. Generate with openssl rand -base64 24. Required for SSO. Tiers: all.
CLIENT_HOSTPANEL_SECRETsecretCHANGE_MESecret the API exchanges the admin SPA's authorization code with, server to server. API refuses to start without it when AUTH_MODE=sso. Required for SSO. Tiers: all.
HOSTPANEL_BACKCHANNEL_LOGOUT_KEYsecretCHANGE_MEShared with the provider for back-channel logout. Generate with openssl rand -hex 24. Must be at least 16 characters on a deployed host. Leave empty only where no provider is connected. Required for SSO. Tiers: all.

Updating to a release that moves the sign-on client package to 5.1 resets the admin panel sessions once: the package now keeps its session cache keys per product, so the sessions stored under the old keys are no longer read. Every administrator signs in again after the update, with no action needed beyond that, and the old entries expire on their own. The package also maps the back-channel logout receiver itself at /api/auth/backchannel-logout, and a sign-in callback that has no matching attempt (a second tab, Back after signing in) now redirects to the sign-in page instead of answering an error body. Nothing needs configuring for either.

Local session settings ​

Local These settings apply only when AUTH_MODE=local.
NameTypeDefaultDescription
SESSION_ACCESS_TOKEN_MINUTESstring15Access-token lifetime in minutes. Sliding renewal re-issues the token while the person keeps working. Tiers: hub, prod, dev.
SESSION_MAX_MINUTESstring720Absolute session age after which token renewal stops and the person must sign in again. Tiers: hub, prod, dev.

Addresses and host names ​

NameTypeDefaultDescription
DOMAINstringyourdomain.comPublic host name of the client portal (e.g., panel.example.com). Must differ from ADMIN_DOMAIN. Required. Tiers: all.
ADMIN_DOMAINstringadmin.yourdomain.comPublic host name of the admin panel. Must differ from DOMAIN. Required. Tiers: all.
ADMIN_BASE_URLstringhttps://admin.yourdomain.comAbsolute URL of the admin panel (scheme, no trailing slash). Base of links the API mails to staff. Required in prod and hub. Tiers: prod, hub.
CLIENT_BASE_URLstringhttps://yourdomain.comAbsolute URL of the client portal (scheme, no trailing slash). Base of links the API mails to clients. Required in prod and hub. Tiers: prod, hub.
NUXT_PUBLIC_BASE_URLstringhttps://panel.example.comPublic URL the client portal JavaScript uses for API calls. Required. Tiers: all.
ADMIN_BASE_URL_PATHstring/Base path the admin SPA is served under (/ or /admin). Read by the admin container at start, not at build. Tiers: hub, prod.
ALLOWED_HOSTSstringpanel.example.test;hostpanel-api;localhostHost names the API answers to, semicolon-separated. Include the public host, hostpanel-api and localhost. Required. Tiers: all.
PANEL_DEV_ORIGINstringhttp://panel.example.testDev-proxy origin the API allows alongside localhost (CORS). Tiers: dev.
SSH_AGENT_SOURCE_ADDRESSESstring—Public address(es) this installation connects to SSH key agents from, comma-separated. New in 0.4.0. Tiers: prod, hub.
PANEL_HOST_ADDRESSESstring—Control panels reachable only over a VPN, as hostname=address pairs, comma-separated. New in 0.4.0. Tiers: prod, hub.

Servers → SSH shows the exact firewall rules once SSH_AGENT_SOURCE_ADDRESSES is set. See SSH key agent.

Keys and encryption ​

ENCRYPTION_KEY protects server passwords, API tokens and access hashes. Never change it on a running installation without a re-encryption plan. Back up .env with every database dump.
NameTypeDefaultDescription
ENCRYPTION_KEYsecretsee .env.exampleMust decode to exactly 32 bytes. Protects encrypted database columns. Generate: openssl rand -base64 32. The example value is a placeholder and is refused outside Development. Required in prod, hub, demo. Tiers: prod, hub, demo.
SESSION_ENCRYPTION_KEYsecret—Key for client portal sessions (AES-256-GCM). 32 random bytes, base64. Changing it signs everyone out. Required in prod, hub, demo. Tiers: prod, hub, demo.
JWT_SECRETsecretsee .env.exampleAt least 32 characters. Placeholder is refused outside Development. Generate: openssl rand -hex 32. Tiers: all.
JWT_ISSUERstringinnovayse-apiIssuer claim stamped into every token. Tiers: all.
JWT_AUDIENCEstringinnovayse-clientsAudience claim verified on every token. Tiers: all.

Database, message queue and cache ​

NameTypeDefaultDescription
POSTGRES_HOSTstringhostpanel-dbDatabase host name. Tiers: all.
POSTGRES_PORTstring5432Database port. Tiers: all.
POSTGRES_USERstringpostgresDatabase user. Tiers: all.
POSTGRES_PASSWORDsecretCHANGE_MEDatabase password. Placeholder is refused outside Development. Required. Tiers: all.
POSTGRES_DBstringinnovayse_devDatabase name. Tiers: all.
RABBITMQ_HOSTstringhostpanel-rabbitmqMessage queue host name. Tiers: all.
RABBITMQ_PORTstring5672Message queue port. Tiers: all.
RABBITMQ_USERstringguestMessage queue user. Tiers: all.
RABBITMQ_PASSWORDsecretCHANGE_MEMessage queue password. Placeholder is refused outside Development. Required. Tiers: all.
REDIS_CONNECTIONstringhostpanel-redis:6379Redis connection string. Used for admin sessions (SSO), data protection key ring, and client portal sign-in sessions. Tiers: all.

Mail ​

Unset or misspelled SMTP_ENCRYPTION stops the API on startup and names this key in the log.
NameTypeDefaultDescription
SMTP_HOSTstringhostpanel-mailhogSMTP relay host. Installer leaves this empty; no mail is sent until it is set. Required in prod and hub. Tiers: all.
SMTP_PORTstring1025SMTP port. Usually 587 (STARTTLS) or 465 (implicit TLS). Tiers: all.
SMTP_USERNAMEstring—Relay username. Tiers: all.
SMTP_PASSWORDsecret—Relay password. Tiers: all.
SMTP_ENCRYPTIONstringnonetls (STARTTLS), ssl (implicit TLS) or none (local catcher only). Required and validated on startup. Tiers: all.
SMTP_FROMstringnoreply@example.comSender address. Tiers: all.
SMTP_FROM_NAMEstringHostpanelSender display name. Tiers: all.
EMAIL_TOstringcontact@yourdomain.comContact form delivery address. Unset form answers 503 CONTACT_NOT_CONFIGURED. Tiers: all.
DEPARTMENT_SUPPORT_EMAILstringsupport@example.comSupport department email on first install. Editable in the admin panel afterwards. Tiers: all.
DEPARTMENT_BILLING_EMAILstringbilling@example.comBilling department email on first install. Tiers: all.
DEPARTMENT_SALES_EMAILstringsales@example.comSales department email on first install. Tiers: all.
DEPARTMENT_GENERAL_EMAILstringhello@example.comGeneral department email on first install. Tiers: all.
TELEGRAM_BOT_TOKENsecret—Telegram bot token for contact form notifications. Both or neither: half a pair refuses startup. Tiers: all.
TELEGRAM_CHAT_IDstring—Telegram chat ID, optional pair. Set both or neither. Tiers: all.

Reverse proxy and trusted proxies ​

Getting the proxy counts wrong breaks rate limiting and order IP tracking. Too low: every visitor shares one rate-limit partition and orders record the wrong IP. Too high: a visitor can spoof their address.

When the installation sits behind one or more proxies, the API and client portal must trust headers about the real visitor's address. The diagram shows the path:

visitor → [extra proxy] → edge (Caddy/nginx) → client portal → API
                                                    ↑
                                         RATE_LIMIT_TRUSTED_PROXY_COUNT
                                         CLIENT_TRUSTED_PROXY_COUNT

Each extra proxy in front of the bundled edge adds 1 to both counts. The shipped stacks have one built-in edge layer, so the default is 1. If you place an extra proxy in front (load balancer, WAF, CDN), increase both counts by 1 per extra layer.

NameTypeDefaultDescription
STACK_NETWORK_SUBNETstring172.30.0.0/24CIDR range of the Docker network the stack creates. Passed to the API as RateLimit__KnownNetworks__0. Pick a range no other network on the host uses. Required. Tiers: hub, prod, dev.
RATE_LIMIT_TRUSTED_PROXY_COUNTstring1Number of proxies in front of the API (RateLimit__TrustedProxyCount). The shipped stacks need 1 (the bundled edge). Add one per extra proxy. Tiers: hub, prod, dev.
CLIENT_TRUSTED_PROXY_COUNTstring1Number of proxies in front of the client portal (NUXT_TRUSTED_PROXY_COUNT). The shipped stacks need 1. Add one per extra proxy. The dev stack fixes this at 0 and does not read this variable. Tiers: hub, prod, demo.

Rate-limit settings (compose override only) ​

The following settings are set directly on the API service in a compose override file, not in .env.example. Use them to tune rate limiting per endpoint.
SettingDefaultDescription
RateLimit__Global__PermitLimit1200Requests allowed per window (applies to every request)
RateLimit__Global__WindowSeconds60Window length in seconds
RateLimit__Auth__PermitLimit15Auth endpoint limit per window
RateLimit__Auth__WindowSeconds60Auth window length in seconds
RateLimit__Upstream__PermitLimit60Upstream (panel API) limit per window
RateLimit__Upstream__WindowSeconds60Upstream window length in seconds
RateLimit__Strict__PermitLimit5Strict endpoints limit per window
RateLimit__Strict__WindowSeconds60Strict window length in seconds
RateLimit__SshKeys__PermitLimit20SSH key endpoints limit per window
RateLimit__SshKeys__WindowSeconds60SSH key window length in seconds
RateLimit__ConcurrentPermitLimit5Maximum concurrent requests from one address
RateLimit__PluginDefault__PermitLimit120Plugin route limit per window, for a route that names no tier. Counted per plugin and per caller (the client account, or the administrator on an admin call)
RateLimit__PluginDefault__WindowSeconds60Plugin default window length in seconds
RateLimit__PluginStrict__PermitLimit20Limit per window for a plugin route that asks for the strict tier (costly or sensitive routes, such as one that sends messages)
RateLimit__PluginStrict__WindowSeconds60Plugin strict window length in seconds
RateLimit__PluginHeavy__PermitLimit6Limit per window for a plugin route that asks for the heavy tier (reports, exports)
RateLimit__PluginHeavy__WindowSeconds60Plugin heavy window length in seconds
RateLimit__PluginCallback__PermitLimit120Limit per window for the public plugin callback door (/api/plugins/{id}/callback/...). Counted per caller address over every plugin and path, declared or not
RateLimit__PluginCallback__WindowSeconds60Plugin callback window length in seconds
RateLimit__PluginStreamPermitLimit3Streaming plugin routes one caller may hold open at once, per plugin
SignInLockout__MaxFailedAttempts5Wrong passwords before lockout
SignInLockout__LockoutMinutes15Minutes an account stays locked (locked sign-in → 423)

MaxFailedAttempts accepts 1–100, LockoutMinutes accepts 1–1440. Values outside these ranges refuse startup.

Plugin routes are limited per plugin and per caller, so one plugin or one account cannot use up the API. A plugin route declares its tier in the plugin manifest (rateLimit: default, strict or heavy); a route that declares none uses the default tier. A refused request answers 429 with Retry-After and X-RateLimit-Remaining. Every plugin tier must be positive and no larger than RateLimit__Global__PermitLimit, the tiers must be ordered heavy <= strict <= default, and RateLimit__PluginStreamPermitLimit must be positive, or startup is refused.

The public plugin callback door (/api/plugins/{id}/callback/...) is rate limited per caller address, and that address is the one the forwarded headers resolve to. It only works as intended when the forwarded headers are configured: set RateLimit__TrustedProxyCount to the number of proxies in front of the API and list them in RateLimit__KnownProxies or RateLimit__KnownNetworks (the bundled stacks do this through STACK_NETWORK_SUBNET). Behind an unconfigured proxy every gateway call shares the proxy's address and one burst refuses all callbacks; with too many trusted hops a sender can write its own X-Forwarded-For and pick its own bucket. The API ignores X-Forwarded-For from any peer that is not a configured proxy.

Edge proxy ​

The edge layer (Caddy on hub, nginx on prod) terminates TLS and routes to the API and client portal.

NameTypeDefaultDescription
EDGE_SCHEMEstringhttps://https:// for automatic Let's Encrypt certificates (default); http:// when your own proxy terminates TLS (then pick free ports). Tiers: hub, prod.
EDGE_HTTP_PORTstring80HTTP port the edge listens on. Tiers: hub, prod.
EDGE_HTTPS_PORTstring443HTTPS port the edge listens on. Tiers: hub, prod.
ACME_EMAILstringadmin@yourdomain.comContact address for Let's Encrypt certificates. Set by installer. Required for hub. Tiers: hub.
EDGE_MAX_BODY_SIZEstring50MLargest request body on the client portal host. Use the M suffix (e.g., 50M). Tiers: hub, prod.
EDGE_ADMIN_MAX_BODY_SIZEstring1MLargest request body on the admin host. Tiers: hub, prod.
EDGE_CLIENT_CSP_SOURCESstring—Extra origins the client portal's CSP allows (space-separated). Add the script and API origins a payment plugin's checkout needs; the default policy names no gateway. Tiers: hub, prod.
NGINX_HTTP_PORTstring80Host HTTP port for the bundled nginx (prod stack, no platform overlay). Tiers: prod.
NGINX_HTTPS_PORTstring443Host HTTPS port for the bundled nginx. Tiers: prod.

Images and versions ​

NameTypeDefaultDescription
IMAGE_TAGstringlocalRelease to run, e.g., 0.4.0 or latest. No leading v. Required for hub and prod. Tiers: hub, prod.
DOCKERHUB_NAMESPACEstringinnovayseDocker Hub user/organisation for hub stack images. Tiers: hub.
IMAGE_REGISTRYstringregistry.example.com/hostpanelRegistry path for prod stack images (e.g., registry.example.com/hostpanel). Required for prod. Tiers: prod.
POSTGRES_IMAGEstringsee .env.exampleFull postgres image reference, pinned to a digest. Tiers: all.
RABBITMQ_IMAGEstringsee .env.exampleFull RabbitMQ image reference, pinned to a digest. Tiers: all.
REDIS_IMAGEstringsee .env.exampleFull Redis image reference, pinned to a digest. Tiers: all.
MAILHOG_IMAGEstringsee .env.exampleFull Mailhog image reference (dev and demo stacks). Tiers: dev, demo.
NGINX_IMAGEstringsee .env.exampleFull nginx image reference (must be the unprivileged build). Tiers: prod.
CADDY_IMAGEstringsee .env.exampleFull Caddy image reference. Tiers: hub.

API and ports ​

NameTypeDefaultDescription
API_PORTstring5148Port the API listens on inside its container. Templated into the edge config, change here only. Tiers: all.
CLIENT_PORTstring3000Port the client portal listens on inside its container. Templated into the edge config, change here only. Tiers: all.
API_GC_SERVERstring0.NET GC mode: 0 workstation, 1 server. Tiers: prod, hub.
API_GC_CONSERVE_MEMORYstring5Memory conservation level, 0–9. Tiers: prod, hub.
API_GC_HEAP_HARD_LIMIT_PERCENTstring75Heap cap as a percentage of container memory. Tiers: prod, hub.

Order numbering and invoice settings (compose override only) ​

Order numbering and invoice settings are not in .env. Set them directly on the API service in a compose override.
SettingDefaultDescription
Orders__NumberPrefixORD-Order number prefix
Orders__NumberDigits4Zero-padded digits (e.g., 0042)
Orders__InvoicePaymentTermDays7Invoice payment term in days (0–365)
InvoicePdf__MaxLines500Maximum line items per PDF
InvoicePdf__MaxConcurrentRenders4Concurrent PDF renders
InvoicePdf__MaxRenderWaitSeconds10Seconds a download waits for a free render slot before answering 503 with Retry-After.

Client portal look and content ​

All these settings control the public-facing storefront and have NUXT_PUBLIC_PORTAL_* environment variable fallbacks. The admin panel's Settings section wins over environment variables once set.

NameTypeDefaultDescription
NUXT_PUBLIC_PORTAL_TEMPLATEstringclassicStorefront template: classic, aurora or nova. Admin Settings overrides this. Tiers: all.
NUXT_PUBLIC_PORTAL_APPS_ENABLEDflagfalseShow the apps launcher in the header. true/1/yes/on. Tiers: all.
NUXT_PUBLIC_PORTAL_CONTACT_EMAILstring—Footer contact email. Empty hides it. Tiers: all.
NUXT_PUBLIC_PORTAL_SOCIAL_TWITTERstring—Twitter/X profile URL. Tiers: all.
NUXT_PUBLIC_PORTAL_SOCIAL_LINKEDINstring—LinkedIn profile URL. Tiers: all.
NUXT_PUBLIC_PORTAL_SOCIAL_FACEBOOKstring—Facebook profile URL. Tiers: all.
NUXT_PUBLIC_PORTAL_HOSTING_DEMO_URLstring—Demo site URL linked from the home products section. Tiers: all.
NUXT_PUBLIC_PORTAL_CONTACT_ADDRESSstring—Postal address shown on the contact page. Tiers: all.
NUXT_PUBLIC_PORTAL_CONTACT_MAP_URLstring—Map link on the contact page. Tiers: all.
NUXT_PUBLIC_PORTAL_STATS_CLIENTSstring—Home page stat: client count (free text). Tiers: all.
NUXT_PUBLIC_PORTAL_STATS_UPTIMEstring—Home page stat: uptime figure. Tiers: all.
NUXT_PUBLIC_PORTAL_STATS_REGIONSstring—Home page stat: regions count. Tiers: all.
NUXT_PUBLIC_PORTAL_HERO_BADGEstring—Short badge text above the home page headline. Tiers: all.
NUXT_PUBLIC_PORTAL_SITE_NAMEstring—Site name for browser title and social previews. Admin Settings wins. Tiers: all.
NUXT_PUBLIC_PORTAL_SITE_TAGLINEstring—Site tagline. Admin Settings wins. Tiers: all.
NUXT_PUBLIC_PORTAL_THEME_DEFAULTstringdarkDefault colour mode: light, dark or system. Tiers: all.
NUXT_PUBLIC_PORTAL_THEME_USER_TOGGLEflagtrueShow the light/dark switch. Only the literal false hides it. Tiers: all.
NUXT_PUBLIC_PORTAL_LOGOstring—Logo URL (light background). Empty uses the built-in mark. Tiers: all.
NUXT_PUBLIC_PORTAL_LOGO_DARKstring—Logo URL (dark background). Falls back to NUXT_PUBLIC_PORTAL_LOGO. Tiers: all.
NUXT_PUBLIC_PORTAL_LOGO_MARKstring—Square mark for compact spaces. Tiers: all.
NUXT_PUBLIC_PORTAL_FAVICONstring—Favicon URL. Tiers: all.
NUXT_PUBLIC_PORTAL_BRAND_PRIMARYstring—Primary brand colour (#rrggbb). Tiers: all.
NUXT_PUBLIC_PORTAL_BRAND_ACCENTstring—Accent brand colour (#rrggbb). Tiers: all.
NUXT_PUBLIC_PORTAL_BRAND_FONT_HEADINGstring—Heading font: inter, noto-sans-armenian, noto-serif-armenian or system. Tiers: all.
NUXT_PUBLIC_PORTAL_BRAND_FONT_BODYstring—Body font. Tiers: all.
NUXT_PUBLIC_PORTAL_GTM_IDstring—Google Tag Manager container ID. Waits for cookie consent. Admin Settings wins. Tiers: all.
NUXT_PUBLIC_PORTAL_CHAT_BASE_URLstring—Live chat server URL. Also a build-time ARG (baked into the image). Tiers: all.
NUXT_PUBLIC_PORTAL_CHAT_WEBSITE_TOKENstring—Chat widget token (default language). Tiers: all.
NUXT_PUBLIC_PORTAL_CHAT_WEBSITE_TOKEN_RUstring—Chat widget token (Russian). Tiers: all.
NUXT_PUBLIC_PORTAL_CHAT_WEBSITE_TOKEN_HYstring—Chat widget token (Armenian). Tiers: all.
NameTypeDefaultDescription
BILLING_PORTAL_URLstring—Billing portal address (no trailing slash). Left empty, handoff links are hidden. Tiers: all.

Plugins ​

Plugin settings are not in .env. Set them on the API service in a compose override.
SettingDefaultDescription
Plugins__InstallPath(empty, falls back to plugins-installed beside the app)Directory where the API installs plugin packages.
Plugins__MaxEntryCount1000Maximum number of files in a plugin zip archive.
Plugins__MaxUncompressedBytes209715200Maximum total uncompressed size of a plugin archive in bytes (200 MiB).
Plugins__MigrationTimeoutSeconds120Longest one plugin migration hook may run after an upgrade, in seconds (1 to 3600). Past it the host stops waiting and keeps the plugin switched off until a later attempt succeeds.
Plugins__MaxViewBytes262144Maximum size in bytes of one plugin view document (a page or slot view file, 256 KiB); a larger file refuses the plugin at load and at install. 1 to 4194304 (4 MiB).
Plugins__TrustedPackageSha256__0, __1, ...n/aSHA-256 hashes of plugin packages to trust unconditionally. Each hash is a separate indexed key.
PluginApi__MaxBodyBytes1048576Largest request body the host reads for a plugin route, in bytes (1 to 67108864).
PluginApi__CallTimeoutSeconds30Seconds the host waits for a plugin route to answer (1 to the ceiling below). Past it the plugin is cancelled through its token and the caller gets PLUGIN_TIMEOUT (504). On a streamed reply it covers the wait for the reply and for the first event and the silence between events, never the length of a stream that keeps sending.
PluginApi__MaxCallTimeoutSeconds600The ceiling for a per route limit (1 to 3600). Every route gets CallTimeoutSeconds today; a route will be able to ask for a longer limit, up to this, once the plugin SDK has a field for it. Must be at least CallTimeoutSeconds.
PluginApi__AbandonWaitSeconds5Seconds, after the call limit, the host waits for a plugin that ignores its cancellation before it abandons the call (1 to 60). The caller gets PLUGIN_TIMEOUT either way.
PluginApi__MaxAbandonedCallsPerPlugin8Most abandoned calls of one plugin that may still be running (1 to 1000). At the limit, new calls to that plugin are refused at once with PLUGIN_TIMEOUT until one of them ends.
PluginApi__StreamHeartbeatSeconds15Seconds a streamed plugin reply may stay silent before the host writes a comment line to keep the connection alive (1 to 300).
PluginApi__StreamEventMaxBytes65536Largest data of one event of a streamed plugin reply, in bytes (1 to 1048576). A plugin that sends a larger event ends the stream with an error event.
PluginSigning__MaintainerKeys__0__KeyId, __PublicKey, ...(shipped in the image)Ed25519 signing key entries for the official plugin maintainers. Shipped in the image; operators do not set these.
PluginSigning__OperatorKeys__0__KeyIdn/aKey ID of an operator-trusted plugin signer. Each entry is a pair of __KeyId and __PublicKey under the same index. With the compose files, set PLUGIN_OPERATOR_KEY_ID. Leave it and the public key empty to add none; setting only one of the two stops the API at start.
PluginSigning__OperatorKeys__0__PublicKeyn/aEd25519 public key of the operator-trusted signer at index 0. Add more signers as __1__KeyId / __1__PublicKey, and so on. With the compose files, set PLUGIN_OPERATOR_PUBLIC_KEY.

Development-only settings ​

The settings in this section are for local development only. Do not use them on servers.
NameTypeDefaultDescription
POSTGRES_HOST_PORTstring5434Host port published by the database container. Tiers: dev.
RABBITMQ_HOST_PORTstring5673Host port published by RabbitMQ. Tiers: dev.
RABBITMQ_MANAGEMENT_HOST_PORTstring15673Host port for the RabbitMQ management UI. Tiers: dev.
MAILHOG_SMTP_HOST_PORTstring1026Host port for the Mailhog SMTP. Tiers: dev.
MAILHOG_UI_HOST_PORTstring8027Host port for the Mailhog web UI. Tiers: dev.
API_HOST_PORTstring5149Host port published by the API container. Tiers: dev.
CLIENT_HOST_PORTstring3001Host port published by the client portal. Tiers: dev.
ADMIN_HOST_PORTstring5174Host port published by the admin panel. Tiers: dev.
CORS_CLIENT_ORIGINstringhttp://localhost:3001Browser origin for the client portal (CORS). Tiers: dev.
CORS_ADMIN_ORIGINstringhttp://localhost:5174Browser origin for the admin panel (CORS). Tiers: dev.
CORS_STAGE_ORIGINstringhttps://stage-panel.example.comBrowser origin for a staging client portal (CORS). Tiers: dev.
CLIENT_DEV_ALLOWED_HOSTSstring—Extra hostnames the client dev server answers to (comma-separated). Tiers: dev.
ADMIN_DEV_ALLOWED_HOSTSstring—Extra hostnames the admin dev server answers to (comma-separated). Tiers: dev.
DEV_FILE_POLLINGflagtruePoll bind mounts for changes (true/false). Needed on Docker Desktop mounts. Tiers: dev.
DEV_NUGET_AUDITflagfalseEnable NuGet package audit inside the dev API container. Tiers: dev.
DEV_NUGET_SIGNATURE_VERIFICATIONflagfalseEnable NuGet signature verification. Tiers: dev.
DEV_SEED_ADMIN_PASSWORDstringAdmin123!Admin account password created by the dev data seeder. Published fixture, not a secret. Tiers: dev.
DEV_SEED_CLIENT_PASSWORDstringTest@12345Client account password created by the dev data seeder. Tiers: dev.
TESTCONTAINERS_HOST_OVERRIDEstringhost.docker.internalDocker host for Testcontainers in the dev API container. Tiers: dev.
ADMIN_API_BASEstring/apiBase path the admin dev server proxies to the API. Tiers: dev.
DB_CPUSstring1.0CPU cap for the database container. Tiers: dev.
DB_MEMORYstring1GMemory cap for the database container. Tiers: dev.
RABBITMQ_CPUSstring1.0CPU cap for RabbitMQ. Tiers: dev.
RABBITMQ_MEMORYstring512MMemory cap for RabbitMQ. Tiers: dev.
REDIS_CPUSstring0.5CPU cap for Redis. Tiers: dev.
REDIS_MEMORYstring256MMemory cap for Redis. Tiers: dev.
MAILHOG_CPUSstring0.2CPU cap for Mailhog. Tiers: dev.
MAILHOG_MEMORYstring256MMemory cap for Mailhog. Tiers: dev.
API_CPUSstring2.0CPU cap for the API. Tiers: dev.
API_MEMORYstring2GMemory cap for the API. Tiers: dev.
CLIENT_CPUSstring1.5CPU cap for the client portal. Tiers: dev.
CLIENT_MEMORYstring2GMemory cap for the client portal. Tiers: dev.
ADMIN_CPUSstring1.0CPU cap for the admin panel. Tiers: dev.
ADMIN_MEMORYstring1536MMemory cap for the admin panel. Tiers: dev.

Demo mode ​

Local Demo mode requires AUTH_MODE=local.
Demo mode requires AUTH_MODE=local and its own POSTGRES_DB. It resets sample data on schedule. Set DEMO_ENABLED=true to activate it.
NameTypeDefaultDescription
DEMO_ENABLEDflagtrueEnable demo mode. Tiers: demo.
DEMO_RESET_INTERVAL_HOURSstring24Hours between database wipes and re-seeds. Tiers: demo.
DEMO_ADMIN_EMAILstringadmin@demo.localDemo admin sign-in email (shown on the sign-in page). Tiers: demo.
DEMO_ADMIN_PASSWORDsecret—Demo admin password. At least 8 characters with upper and lower case. No default; compose refuses to start without it. Required for demo. Tiers: demo.
DEMO_CLIENT_EMAILstringclient@demo.localDemo client sign-in email. Tiers: demo.
DEMO_CLIENT_PASSWORDsecret—Demo client password. At least 8 characters with upper and lower case. Required for demo. Tiers: demo.
DEMO_CONTACT_EMAILstring—Contact email shown in the demo storefront footer. Empty keeps the fictional placeholder. Tiers: demo.
DEMO_CONTACT_PHONEstring—Contact phone shown in the demo storefront. Tiers: demo.
DEMO_SMTP_PORTstring1025Port of the demo's Mailhog inside the network. Tiers: demo.
DEMO_REDIS_PORTstring6379Port of the demo's Redis inside the network. Tiers: demo.
DEMO_SESSION_ENCRYPTION_KEYsecret—Session encryption key for the demo portal. Use a separate value from the production one. Required for demo. Tiers: demo.
DEMO_PUBLISH_ADDRESSstring127.0.0.1Address the demo's published ports bind to. Loopback keeps them off the network. Required for demo. Tiers: demo.
DEMO_SMTP_ENCRYPTIONstringnoneDemo mail catcher encryption. Use none. Required for demo. Tiers: demo.
DEMO_API_HOST_PORTstring5150Host port for the demo API. Required for demo. Tiers: demo.
DEMO_CLIENT_HOST_PORTstring3002Host port for the demo client portal. Required for demo. Tiers: demo.
DEMO_ADMIN_HOST_PORTstring5175Host port for the demo admin panel. Required for demo. Tiers: demo.
DEMO_ADMIN_BASE_URLstringhttp://localhost:5175Absolute URL of the demo admin panel. Required for demo. Tiers: demo.
DEMO_CLIENT_BASE_URLstringhttp://localhost:3002Absolute URL of the demo client portal. Required for demo. Tiers: demo.
DEMO_MAILHOG_UI_HOST_PORTstring8028Host port for the demo Mailhog UI. Tiers: demo.
DEMO_NETWORK_SUBNETstring—Required. CIDR range of the demo stack internal network. Not in .env.example; docker-compose.demo.yml refuses to start without it. Example: 172.28.0.0/16. Tiers: demo.
DEMO_EDGE_NETWORK_SUBNETstring—Required. CIDR range of the demo edge network. Not in .env.example; docker-compose.demo.yml refuses to start without it. Example: 172.29.0.0/16. Tiers: demo.

Startup refusals ​

The API validates secrets and key settings before it accepts any request. If a check fails it logs the exact key and exits. Common causes:

Symptom in the logCauseFix
Secret still CHANGE_ME or too shortJWT_SECRET, ENCRYPTION_KEY, POSTGRES_PASSWORD, RABBITMQ_PASSWORD or a configured HOSTPANEL_BACKCHANNEL_LOGOUT_KEY holds a placeholder or is too short.Generate a real value with openssl rand.
SMTP_ENCRYPTION invalidValue is unset, misspelled or not one of tls, ssl, none.Set it to the correct value.
Only one of an optional pair is setTELEGRAM_BOT_TOKEN set but TELEGRAM_CHAT_ID empty, or vice versa.Set both or clear both.
CLIENT_HOSTPANEL_SECRET missingAUTH_MODE=sso but CLIENT_HOSTPANEL_SECRET is empty.Set the secret or switch to AUTH_MODE=local.
HOSTPANEL_BACKCHANNEL_LOGOUT_KEY too shortValue is shorter than 16 characters on a deployed host.Generate with openssl rand -hex 24.
Order number setting invalidOrders__NumberPrefix and Orders__NumberDigits cannot produce a valid order number, or Orders__InvoicePaymentTermDays is out of range (0–365).Correct the values in the compose override.
CORS_* origin invalidAn allowed origin is not a valid absolute URL (e.g. missing scheme).Fix the origin in .env.

Error codes ​

Error codes returned to the client with their HTTP status and message:

CodeStatusMessage
CONTACT_NOT_CONFIGURED503"The contact form is not available on this deployment. Please use the email address or phone number shown on this page."
SIGN_IN_ACCOUNT_LOCKED423"Too many wrong passwords. This account is locked for a while, try again later."
Was this page helpful?

Released under the AGPL-3.0 License.