Skip to main content

Installation

Bundle Deployment

The CTMS platform ships as a single self-contained bundle — everything needed to install, configure, and run the platform in one package. No GitHub token, no git clone, no manual Docker builds. One command gets you running.

SERVER_HOST=<your-ip> ./zynctl.sh full-deploy
Supported Operating Systems

The zynctl.sh script is written and tested for RHEL-family Linux distributions:

  • Rocky Linux 9 / 10
  • AlmaLinux 9
  • Amazon Linux 2023
  • RHEL 9 / CentOS Stream 9

The bootstrap step installs Docker and system dependencies using dnf. Other distributions (Ubuntu, Debian) are not currently supported by the automated bootstrap — you would need to install Docker manually first.


Prerequisites

Before you begin, make sure you have the following ready:

RequirementDetails
VM / Server IPA publicly reachable IP address for your server. You will configure this as SERVER_HOST.
OSRocky Linux 9/10, AlmaLinux 9, Amazon Linux 2023, or RHEL 9
RAM8 GB minimum (16 GB recommended)
CPU4 vCPU minimum (8 vCPU recommended)
Disk50 GB free
Root AccessSSH root or sudo access to the server
NetworkOutbound internet for Docker Hub image pulls
Docker Hub AccountRequired — to avoid pull rate limits (anonymous: 100 pulls/6h). Sign up free →
Docker Hub Rate Limits

Without Docker Hub credentials, anonymous pulls are limited to 100 per 6 hours. A team of 4 sharing a server IP will hit this limit quickly. Always configure DOCKER_USERNAME and DOCKER_PASSWORD in zynctl.conf before deploying.

Ports Used

The following ports must be free on the server:

PortService
3000Zynexa (CTMS App)
3001Sublink (Mobile)
3200Elementary Reports
5080OpenObserve
8000Supabase Studio
8001ODM API
8006MCP Server (AI)
8080Frappe
9080API Gateway (KrakenD)

Quick Start

1. Download the bundle

Download the latest install bundle using the presigned download URL provided by your Zynomi account representative.

# Paste the complete download URL provided by your account representative
curl -LO '<YOUR_DOWNLOAD_URL>'

Your download URL will look like this:

https://zynomi-ctms.s3.us-east-2.amazonaws.com/zynctl-bundle-<version>.tar.gz
?X-Amz-Algorithm=AWS4-HMAC-SHA256
&X-Amz-Credential=<credential>
&X-Amz-Date=<timestamp>
&X-Amz-Expires=<seconds>
&X-Amz-SignedHeaders=host
&X-Amz-Signature=<signature>

Your account representative will provide the complete URL with all parameters filled in — paste it as-is. The -LO flag saves the file with its original name automatically.

Download Access

Install bundles are hosted on a private S3 bucket. Each client receives a time-limited download token during onboarding. If your token has expired, contact your account representative or email contact@zynomi.com for a fresh one. See the Downloads FAQ for more details.

2. Install tar (if not already present)

sudo dnf install -y tar

3. Extract and configure

tar xzf zynctl-bundle-<version>.tar.gz
cd zynctl-bundle-<version>

# Create config
cp zynctl.conf.example zynctl.conf

Edit zynctl.conf with your server IP and Docker Hub credentials:

# ── Required ──────────────────────────────────
SERVER_HOST=<your-server-ip>

# ── Docker Hub (required to avoid rate limits) ─
DOCKER_USERNAME=<your-dockerhub-username>
DOCKER_PASSWORD=<your-dockerhub-password>

4. Deploy

# One command: bootstrap + deploy
./zynctl.sh full-deploy

Or step-by-step:

./zynctl.sh bootstrap    # Install Docker, Compose, system tuning
exit # Re-login for Docker group membership
ssh root@<server-ip>
cd zynctl-bundle-<version>
./zynctl.sh deploy # Full 12-step deploy

5. Verify

./zynctl.sh health

Deployment takes ~10–15 minutes. All Docker images are pre-built — nothing compiles on the server.


What deploy Does

StepAction~Time
1Copy bundle to /opt/ctms-deployment5s
2Create .env.production from template, patch IP, generate secrets5s
3Create ctms-network, authenticate Docker Hub2s
4Start Supabase (13 services), extract service role key60s
5Seed CTMS tables into Supabase30s
6Start Frappe, wait for site creation and backend API readiness120s
6bWait for Frappe setup container to exit (ensures token is ready)10–120s
7Extract Frappe API token from setup container logs10s
8Force-pull & run CTMS Init (DocTypes → Custom Fields → RBAC → Item Groups → Master Data → Practitioner)60s
9Pull all CTMS Docker images60s
10Start CTMS platform (core + analytics + observability)30s
11Health-check 9 endpoints, seed 4 demo users30s
12Print service URLs and credentials

Commands Reference

Setup

CommandDescription
./zynctl.sh bootstrapInstall Docker, Compose, tune system
./zynctl.sh deployFull first-time deployment
./zynctl.sh full-deployBootstrap + Deploy in one shot
./zynctl.sh resume-deployResume from Step 6b (when Supabase + Frappe are already running)

Operations

CommandDescription
./zynctl.sh statusShow running containers
./zynctl.sh healthCheck all service endpoints
./zynctl.sh seed-usersSeed demo users (idempotent)
./zynctl.sh logs [service]View container logs
./zynctl.sh stopStop all stacks (reverse order)
./zynctl.sh restartRestart CTMS core services
./zynctl.sh updatePull latest images + restart
./zynctl.sh refresh-tokenRe-generate Frappe API token and patch .env.production
./zynctl.sh post-snapshotFix IPs, tokens, and URLs after cloning from a snapshot
./zynctl.sh destroyRemove everything including data (irreversible)

Diagnostics

CommandDescription
./zynctl.sh env-checkValidate .env.production for placeholders
./zynctl.sh infoShow version, config, and system info

Services After Deployment

ServiceURLPurpose
Zynexahttp://<IP>:3000Main CTMS application
Sublinkhttp://<IP>:3001Mobile companion app
API Gatewayhttp://<IP>:9080KrakenD gateway
Cube.jshttp://<IP>:4000Analytics semantic layer
MCP Serverhttp://<IP>:8006AI integration
ODM APIhttp://<IP>:8001ODM document service
Grafanahttp://<IP>:3100Analytics dashboards
OpenObservehttp://<IP>:5080Observability
Elementary Reportshttp://<IP>:3200dbt data quality reports
Supabase Studiohttp://<IP>:8000Database management
Frappehttp://<IP>:8080ERP / DocType engine

Default Credentials

AccountUsernamePassword
Demo — Platform Adminkiran.v@zynomi.com●●●●●●
Demo — Study Coordinatormichael.x@zynomi.com●●●●●●
Demo — Study Designerroshini.s@zynomi.com●●●●●●
Demo — Principal Investigatorpeter.p@zynomi.com●●●●●●
Frappe AdminAdministrator●●●●●●
OpenObserveadmin@ctms.local●●●●●●
Grafanaadmin@ctms.local●●●●●●
info

All demo users share the same default password. Run ./zynctl.sh seed-users to see credentials printed in the terminal, or check the deploy log output.


Configuration

zynctl.conf

# Server IP (required — or pass via SERVER_HOST env var)
SERVER_HOST=203.0.113.50

# Deploy directory (default: /opt/ctms-deployment)
# DEPLOY_PATH=/opt/ctms-deployment

# Docker Hub credentials (required to avoid rate limits)
DOCKER_USERNAME=your-dockerhub-username
DOCKER_PASSWORD=your-dockerhub-password

All settings can also be passed as environment variables:

SERVER_HOST=1.2.3.4 DOCKER_USERNAME=myuser DOCKER_PASSWORD=mypass ./zynctl.sh deploy

Auto-Patched Variables

These are set automatically during deploy — no manual editing needed:

VariableSource
EC2_PUBLIC_IPFrom SERVER_HOST
NEXTAUTH_URLhttp://<SERVER_HOST>:3000
NEXTAUTH_SECRETAuto-generated (openssl rand)
SUPABASE_SERVICE_ROLE_KEYExtracted from Supabase config
FRAPPE_API_TOKENGenerated via Frappe backend

Optional (post-deploy)

Edit /opt/ctms-deployment/.env.production to set:

VariablePurpose
OPENAI_API_KEYMCP AI chat features
ACME_EMAILLet's Encrypt HTTPS (when using a domain)

Recovery: resume-deploy

If the deploy dies mid-way (e.g., network timeout, Docker rate limit) but Supabase and Frappe are already running:

cd /opt/ctms-deployment
./zynctl.sh resume-deploy

This picks up from Step 6b (wait for setup container) through Step 12 (health checks + summary). It verifies Supabase and Frappe containers are running before proceeding.


Optional: Seed Demo Data

The bundle deployment automatically runs platform provisioning (DocTypes, RBAC, master data, practitioner) and seeds 4 demo users during Step 11. If you skipped the user seeding step or want to add demo patients for testing:

# Seed 4 demo users (idempotent — safe to re-run)
./zynctl.sh seed-users

# Seed 20 synthetic demo patients (optional)
cd /opt/ctms-deployment
DC="docker compose -f docker-compose.yml -f docker-compose.prod.yml --env-file .env.production"
$DC --profile init run --rm ctms-patient-seed

For detailed provisioning options — dry-run mode, selective stages, environment variables — see the Platform Provisioning Commands recipe.


Bundle Contents

zynctl-bundle-<version>/
├── zynctl.sh # Platform controller
├── zynctl.conf.example # Config template (Docker Hub creds included)
├── VERSION
├── .env.example # Environment template
├── docker-compose.yml # Base compose stack
├── docker-compose.prod.yml # Production overlay (IP-based ports)
├── caddy/ # Reverse proxy configs
├── config/ # OTEL, Fluent Bit configs
├── ctms-api-gateway/configs/ # KrakenD API gateway
├── scripts/frappe-setup/ # Frappe setup scripts (entrypoint, seed, token gen)
├── supabase/ # Supabase stack (13 services)
└── frappe-marley-health/ # Frappe stack

What's Next?

After a successful deployment, run the Deployment Verification recipe to confirm all 10 services are healthy and seed data was provisioned correctly. It includes a one-shot verification script and commands to manually seed the Healthcare Practitioner, demo users, and demo patients if needed.