Hosting and environments
This page explains where and how a Stack9 instance runs: how the container image is built, which AWS services it runs on, how environments are laid out, and where data lives. It is written for developers and architects who need to understand the runtime their configuration lands in.
What is a Stack9 instance at runtime?
Stack9 Core is distributed as a Docker container image. Each client's instance is a dedicated instance image, built by layering the client's own configuration (entities, queries, screens, automations, MCP configs, custom code) on top of the standard Stack9 Core base image.
Two properties follow from this layering:
- Isolation. Each client's instance is its own image at its own hostname: an isolated application layer.
- A common upgrade path. April9 rebuilds the base image and each client's instance image centrally, so a platform release applies to a customised instance without being blocked by, or breaking, its customisations. See Release and upgrade model.
What happens when a container starts
Every container start runs the bootstrap in apps/core/src/bootstrap.ts. It applies the framework's own database migrations, then the instance's migrations from its built dist/database/migrations, synchronises the database schema with the instance's entity definitions, registers the Console app, and reconciles cron jobs. Bootstrap is designed to be idempotent: it runs on every restart and must stay safe against a partially completed earlier run. This is what lets a release bring the new schema and the application version that depends on it into service together, without a manual migration step.
Why AWS, and why this shape
Stack9 is built to use AWS-native services by default, and April9 is an AWS partner. The infrastructure pattern follows the AWS Well-Architected Framework and is the same pattern every Stack9 instance runs, so scaling and resilience are properties of the architecture rather than something added per engagement. A named AWS Solutions Architect reviews the cloud architecture, the AI workload deployment and cost optimisation during design and before go-live.
How it works
AWS service stack
| Service | Role |
|---|---|
| ECS | Container orchestration for Stack9 instances |
| RDS Aurora (serverless) | Database, autoscaling |
| S3 | Document binaries and audit record versions |
| SQS | Message queuing |
| EventBridge | Event scheduling |
| API Gateway | Consolidation of external system integrations |
| Cognito | Portal identity layer, fronting the client's identity provider |
| CloudTrail | Infrastructure-level audit |
| Bedrock AgentCore | Runtime for Stack9 AI Agents |
| CloudWatch | Infrastructure and application monitoring with configurable alert thresholds |
| AWS WAF and network-level filtering | Filtering of distributed denial-of-service and other malicious traffic before it reaches the application tier |
The database sits in a secure subnet within a private VPC, with no direct internet exposure: only the application's running containers can reach it.
Deployment models
The container-based architecture supports several deployment models from one codebase.
| Model | Summary | When it fits |
|---|---|---|
| Cloud-native / containerised (recommended) | Instances run on AWS ECS and supporting serverless services. The client owns the AWS account; April9 provides managed operation | Government and enterprise. Offered as a Managed Hosted Service in a dedicated, single-tenant AWS environment in Sydney (ap-southeast-2), with AWS consumption on-charged at cost and the account transferable to the client |
| PaaS | The same managed ECS model, described as platform-as-a-service for procurement frameworks that ask for it | As above |
| Hybrid / self-hosted | As a standard Docker image, Stack9 Core can run outside AWS | Azure is technically supported with some performance trade-offs. Other infrastructure is not recommended without further validation |
| SaaS (multi-tenant) | Shared hosting resources across clients to reduce cost | Cost-driven workloads only. Not recommended where full infrastructure isolation is required, and not proposed where personal information is in scope |
The hosting and deployment pattern is a discovery deliverable, documented in the Technical Solution Design and approved by the client before any environment is provisioned.
Environment layout
A typical instance runs three environments across two AWS accounts:
- Production sits alone in its own account, so no non-production activity, credential or misconfiguration can reach it.
- DEV and UAT share the non-production account but are isolated from each other at the application and data layer, each with its own configuration and secrets.
- All three are provisioned as infrastructure as code from the same definitions through automated pipelines, so they are reproducible and consistent, and a disaster-recovery rebuild is a redeploy rather than a repair.
- No client production data is used in non-production. Test data is synthetic, generated against the domain model and the agreed test scenarios.
- UAT and Production can be published under client-issued subdomains (for example
solution-uat.client.gov.au), delegated through the client's DNS, with TLS certificates provisioned against the client-issued name.
Local, DEV, UAT and Production serve identical MCP configs. Each instance's MCP endpoint labels itself with the instance name, ENVIRONMENT_TYPE and host (for example Pages MCP [my-app · UAT · uat-my-app.example.com]), and the built-in stack9_whoami tool returns the same details. Set ENVIRONMENT_TYPE per environment so agents and developers can tell them apart. See Connect Claude Code to a Stack9 MCP endpoint.
Autoscaling
Stack9 instances deploy on fully autoscaling infrastructure:
- a serverless database (RDS Aurora);
- serverless containers that scale on memory, CPU or HTTP request volume;
- queue-based workloads that additionally scale on queue depth and processing load.
Hosting cost therefore follows actual usage rather than capacity sized for peak demand all year. Integrations into a client's own systems can be queued and throttled, so a spike in portal traffic does not become an equivalent spike on the client's systems of record.
Performance targets
| Target | Position |
|---|---|
| Transactional response within 3 seconds | Conventional transactions (page and data requests, form-step submissions, validation, saves, document uploads, status queries) complete well within this. Data capture is decoupled from processing: the request is acknowledged once data is safely captured, and longer-running work is queued behind it |
| AI-generated responses | The stated exception. An answer involving model inference and retrieval is bounded by the model and can exceed 3 seconds. Responses stream, and AI response times are reported separately from transactional ones |
| Administrative concurrency | No limit on concurrent administrative users. Bulk administrative operations run through the queue rather than holding a session |
Load and stress testing is run in a production-like environment before go-live, including concurrent administrative load, and pushed past the target profile to the point of degradation so the actual limit is known.
Data residency
| Element | Location |
|---|---|
| Production workloads, metadata, logs | AWS ap-southeast-2 (Sydney) |
| Backups (point-in-time recovery, daily snapshots, monthly full backups) | Replicated to AWS ap-southeast-4 (Melbourne) |
| Disaster recovery | ap-southeast-4 (Melbourne) |
| AI processing (Stack9 AI Agents on Amazon Bedrock AgentCore): inference, prompts, retrieved content, responses, indexed content | ap-southeast-2 (Sydney) |
| Support access | April9's onshore Australian team only |
| Network egress | Restricted to Australian regions |
All other AWS regions are disabled by default in April9's deployment templates. No data leaves Australian AWS regions: the cross-region replication to Melbourne provides disaster-recovery resilience while keeping all data within Australia.
Operational notes for developers
SERVER_BASE_URLmust be a usable URL. It is the OAuth issuer and the base of every MCP resource identifier. If it cannot be parsed, the MCP endpoint answers503rather than accept tokens it cannot audience-check. See MCP Server.- The MCP endpoint is stateless. Every request stands alone, so running several Core replicas needs no sticky routing for MCP traffic.
- OAuth grant state lives in the cache. Pending authorisation requests, authorisation codes and refresh tokens for MCP clients are held in the instance's cache service (Redis), so it must be shared across replicas.
Limits
- AWS is where Stack9 is optimised. Azure works with performance trade-offs; anything else needs validation before it is offered.
- Multi-tenant SaaS trades isolation for cost. It is not offered where infrastructure isolation is required or where personal information is in scope.
- Load evidence and volume profiling. Autoscaling is a property of the architecture, but volume profiling for a specific new workload is still a discovery activity, and a total-user figure is not a concurrency figure.
- Latency and availability commitments cover the supplier-controlled path only, not the client's own WAN, carrier or egress.
- AI response times are model-bound and reported separately.
Related
- Backup and disaster recovery: availability, RPO, RTO and retention
- Release and upgrade model: how releases reach instances
- Upgrading an instance