For AI agents: a documentation index is available at /llms.txt. A markdown version of this page is available at /guide/self-hosted/get-started/architecture.md.

Self-hostedGet started

Architecture

The services, volumes, ports and data stores that make up a deployed Enterprise instance.

Knowing what runs where is what makes backup, migration and troubleshooting straightforward rather than guesswork.

#The container stack

A Docker deployment defines four services:

ServicePurposePort
orangescrum-appThe application8080
orangescrum-postgresdbMain PostgreSQL database5432 (internal)
orangescrum-reportsAdvanced Dashboard (Superset)8088
orangescrum-reports-dbSuperset's own PostgreSQL databaseinternal

Two databases, not one

Reporting runs on Superset, which keeps its own metadata database separate from the application's. Both must be backed up โ€” a backup covering only the main database restores an instance with no dashboards.

The reports service depends on its database being healthy before it starts, so on a cold boot expect it to come up last. Allow a minute or two before concluding something is broken.

#Persistent volumes

Four named volumes hold everything that must survive a container rebuild:

VolumeMounted atContents
orangescrum-app-files/var/www/html/webroot/filesUploaded files and attachments
orangescrum-app-config/var/www/html/configApplication configuration
orangescrum-postgres-data/var/lib/postgresql/dataMain application database
orangescrum-reports-data/var/lib/postgresql/dataSuperset reports database

Volume names are prefixed by the compose project

On disk they appear as orangescrum-ee_orangescrum-app-files and so on. Always confirm with docker volume ls before writing backup or restore commands โ€” guessing the prefix is the most common cause of a restore that silently populates nothing.

#Data outside Docker

Not everything lives in a volume:

ItemTypical locationWhy it matters
Application data root/data (or your configured path)Application files on the VM host
Host config/etc/app/ or the app rootEnvironment-specific settings
Cron jobs and scripts/etc/cron.d/ or the app folderScheduled digests and reminders
Compose definitiondocker-compose.ymlThe stack itself
Reports image buildosreports.DockerfileCustom Superset build
Secrets./secrets/Plaintext service passwords

#The secrets directory

Four files hold credentials the services read at startup:

FileUsed by
secrets/postgres_password.txtMain database
secrets/reports_admin_user.txtReports service
secrets/reports_admin_email.txtReports service
secrets/reports_admin_password.txtReports service

These are plaintext credentials

Anything that backs up the secrets directory produces an archive containing live passwords. Store those archives encrypted, restrict who can read them, and never put the directory in version control.

#Traditional deployment

Without containers the shape is the same, just managed by the host:

  • PHP-FPM behind Apache or Nginx, document root at webroot/
  • PostgreSQL as a system service
  • Attachments under webroot/files, configuration in config/
  • Cron entries for scheduled jobs

Everything above the document root must be unreachable over HTTP.

#Background jobs

Some behaviour depends on scheduled work rather than the request cycle:

๐Ÿ“ฌDaily Catch-Up

The record is written immediately; the email fires from a background job.

โฐTask reminders

Stored against the task, delivered by a scheduled job at the chosen time.

If digests never arrive, check the scheduler first

The data being present in the database does not mean delivery ran. Confirm the cron entries survived your install or migration โ€” they live outside Docker and are easy to lose.

#Request path

java
Browser
  โ†’ Load balancer / reverse proxy   (TLS terminates here)
    โ†’ orangescrum-app  :8080
      โ†’ orangescrum-postgresdb  :5432
      โ†’ orangescrum-reports     :8088  (Advanced Dashboard)
        โ†’ orangescrum-reports-db

TLS terminates at the proxy; the application itself listens on plain HTTP inside the network. That is why 443 is what you expose and 8080 is what you do not.