Hosting Platforms
Choose the database and migration model before selecting a hosting service. For multiple Roster instances, follow the High Availability architecture. Every production deployment needs HTTPS, stable secrets, health checks, centralized logs, and appropriate backup coverage.
SQLite requires one Roster instance and a durable block volume mounted with
local filesystem semantics at /data. SQLite’s WAL mode does not support
network filesystems such as NFS, EFS, or SMB. Use PostgreSQL when a hosting
service provides only ephemeral or network-mounted storage. Follow the
SQLite backup procedure
for online and hosted-container backups.
Choose the runtime and database together:
| Service | SQLite support | PostgreSQL support |
|---|---|---|
| ECS on Fargate | No for ECS services; task EBS volumes are not retained | Enterprise; required for production Roster |
| App Runner (existing customers) | No; its container filesystem is ephemeral | Enterprise; required for production Roster |
| EKS | One pod with an EBS-backed block PersistentVolume | Enterprise; required for multiple Roster pods |
App Runner is stateless and uses ephemeral
storage, so do
not deploy SQLite there. AWS closed App Runner to new
customers;
this guidance applies only to existing App Runner users. ECS deletes EBS volumes
attached to service-managed tasks when those tasks
terminate,
so Fargate services must use PostgreSQL for persistent Roster data. For EKS
SQLite, run exactly one Roster pod with an EBS-backed block PersistentVolume
and do not use EFS. Store ROSTER_AUTH_SECRET, provider credentials, license
values, and encryption keys in AWS Secrets Manager or SSM Parameter Store. Use
Amazon RDS or another managed PostgreSQL 17/18 service for Fargate, App Runner,
and high-availability deployments.
Google Cloud
Section titled “Google Cloud”| Service | SQLite support | PostgreSQL support |
|---|---|---|
| Cloud Run | No; available volume types do not meet SQLite locking requirements | Enterprise; required for production Roster |
| GKE | One pod with a Persistent Disk-backed PersistentVolume at /data | Enterprise; required for multiple Roster pods |
Cloud Run NFS volumes do not support file
locking,
and Cloud Storage FUSE is not fully POSIX-compliant and does not provide file
locking.
Use Cloud SQL or another managed PostgreSQL 17/18 service with Cloud Run. For
GKE SQLite, run exactly one Roster pod and use a block-backed Persistent Disk,
not NFS or Cloud Storage FUSE. Store secrets in Secret Manager and set
ROSTER_AUTH_URL to the final public HTTPS origin.
| Service | SQLite support | PostgreSQL support |
|---|---|---|
| Azure Container Apps | No; persistent mounts use Azure Files SMB or NFS | Enterprise; required for production Roster |
| Azure App Service for Containers | No; storage mounts are not supported for local databases | Enterprise; required for production Roster |
| AKS | One pod with a Managed Disk-backed volume at /data | Enterprise; required for multiple Roster pods |
Azure Container Apps persistent volumes use Azure Files SMB or
NFS. Azure App
Service explicitly says not to use storage mounts for SQLite or applications
that require file locks.
Use Azure Database for PostgreSQL or another managed PostgreSQL 17/18 service
with those managed web runtimes. For AKS SQLite, run exactly one Roster pod on a
Managed Disk-backed volume. Store secrets in Key Vault and set
ROSTER_AUTH_URL to the final public HTTPS origin.
Fly.io
Section titled “Fly.io”Fly.io can host either Roster deployment shape. Choose the topology before creating the app:
- Standalone SQLite: run exactly one Machine and mount a Fly Volume at
/data. Keep stable runtime secrets, back up the volume, and do not scale the app horizontally. - PostgreSQL HA: run two or more stateless Machines without a Fly Volume, connect them to PostgreSQL 17 or 18 writer and reader endpoints, and follow the High Availability guide.
For standalone SQLite, create the persistent volume and deploy one Machine:
Save a fly.toml for the app before deploying. Replace the example app name
and region with the values selected for the deployment:
app = "your-roster-app"primary_region = "yyz"
[build]image = "advantys/roster:1.2.0"
[env]HOST = "0.0.0.0"PORT = "3000"ROSTER_DATA_DIR = "/data"
[[mounts]]source = "roster_data"destination = "/data"
[http_service]internal_port = 3000force_https = trueauto_stop_machines = "stop"auto_start_machines = truemin_machines_running = 0Then create the app and volume, save the printed bootstrap password, configure the secrets, and deploy exactly one Machine:
app_name=your-roster-appregion=yyzbootstrap_admin_password='Roster-1!'"$(openssl rand -hex 24)"
printf 'Save this bootstrap admin password now: %s\n' "$bootstrap_admin_password"
flyctl apps create "$app_name"flyctl volumes create roster_data -a "$app_name" --region "$region" --size 1
flyctl secrets set -a "$app_name" \ "ROSTER_AUTH_URL=https://${app_name}.fly.dev" \ "ROSTER_AUTH_SECRET=$(openssl rand -base64 48)" \ "ROSTER_BOOTSTRAP_ADMIN_PASSWORD=$bootstrap_admin_password" \ "ROSTER_PROVIDER_SECRET_ENCRYPTION_KEY=$(openssl rand -base64 48)"
flyctl deploy -a "$app_name" --ha=falseflyctl scale count 1 -a "$app_name"
unset bootstrap_admin_passwordConfirm https://your-roster-app.fly.dev/health/ready returns a ready response,
then sign in at the app URL. The bootstrap password is needed only for a new or
reset database. After the administrator exists and login succeeds, remove it:
flyctl secrets unset ROSTER_BOOTSTRAP_ADMIN_PASSWORD -a "$app_name"Keep the auth secret and provider-encryption key configured for every subsequent deploy.
This standalone shape can experience downtime when the Machine, its host, or its local volume is unavailable. Keep tested off-host backups; do not create a second SQLite Machine because Fly Volumes do not replicate data between Machines.
For PostgreSQL HA, provision and test the database, read replica, migration job, shared connector storage, secrets, and failover procedure before scaling Roster. Fly secrets reach every Machine in an app, so keep the privileged database URL in a separate private migrator app. Never add the migrator URL to the runtime app. Roster does not provide an automatic SQLite-to-PostgreSQL data migration.
Kubernetes
Section titled “Kubernetes”For Kubernetes-based platforms, standalone SQLite uses one Roster instance and
a PersistentVolumeClaim mounted at /data. High
availability uses two or more Roster
instances and an external PostgreSQL cluster.
Core runtime requirements:
- one
advantys/rostercontainer per pod containerPort: 3000- readiness on
/health/readyand liveness on/health/live - secrets injected as environment variables
- ingress with HTTPS and a stable public hostname
SQLite deployments additionally require a block-backed PersistentVolumeClaim
mounted at /data; do not use an NFS-backed StorageClass. Roster instances in
an HA deployment use
ROSTER_DEPLOYMENT_MODE=ha to coordinate rate limits and workers through
PostgreSQL.
Render
Section titled “Render”Render can run the published Docker image and
offers managed PostgreSQL. A persistent disk
mounted at /data can support a standalone SQLite deployment when it provides
local filesystem semantics, but disk-backed services cannot scale to multiple
instances. Use PostgreSQL and stateless Roster instances for high availability.
Railway
Section titled “Railway”Railway can deploy the Docker
image with public networking, variables, volumes, and PostgreSQL services. Mount
a volume with local filesystem
semantics at /data for standalone SQLite. Railway does not allow service
replicas with a volume attached. Use PostgreSQL and stateless Roster instances
for high availability.
DigitalOcean App Platform
Section titled “DigitalOcean App Platform”DigitalOcean App Platform can deploy container images and integrate with managed databases and Spaces object storage. Its local filesystem is ephemeral, so use PostgreSQL for production and S3-compatible Spaces for connector files.
Heroku
Section titled “Heroku”Heroku deploys Docker images through the Heroku Container Registry and integrates with Heroku Postgres. Dyno filesystems are ephemeral and do not support mounted volumes. Use PostgreSQL and remote connector storage; do not use SQLite for production.
For every PostgreSQL deployment, keep the schema-owning migration credential
separate from the restricted runtime credential. Use S3 or SFTP connectors when
runtime instances do not share durable /data storage. For HA, configure the
writer endpoint with ROSTER_DATABASE_URL and read-only endpoints with
ROSTER_DATABASE_REPLICA_URLS.
Return to the Deployment Overview for the production checklist and post-deployment steps.