Customer Deployment

This guide covers how customers deploy Scaleout Edge on their own infrastructure — either on a server they already manage, or on a cloud provider (AWS or GCP) provisioned via Terraform.

In both cases the starting point is a release bundle: a self-contained archive of deployment scripts and a pre-built Docker Compose configuration, distributed through the Scaleout Harbor registry.


Prerequisites

A Harbor robot account (username and password) is required for both deployment paths. Your Scaleout representative will provide these credentials.

Compose deployment (on-premise)

  • Linux or macOS with Bash 4+ (on Windows use WSL2)

  • Docker Engine 24+ with the Compose plugin

  • Python 3.8+

Cloud deployment (Terraform)


Step 1: Install ORAS

Release bundles are stored as OCI artifacts on Harbor. You need the ORAS CLI to pull them.

  • macOS
  • Linux (amd64)
  • Windows
brew install oras
VERSION=$(curl -fsSL https://api.github.com/repos/oras-project/oras/releases/latest \
    | python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'].lstrip('v'))")
curl -LO "https://github.com/oras-project/oras/releases/download/v${VERSION}/oras_${VERSION}_linux_amd64.tar.gz"
tar -zxf "oras_${VERSION}_linux_amd64.tar.gz" oras
sudo mv oras /usr/local/bin/
rm "oras_${VERSION}_linux_amd64.tar.gz"
winget install -e --id ORASProject.ORAS

Verify:

oras version

Step 2: Authenticate to Harbor

Log in with your Harbor robot account. Credentials are stored in ~/.docker/config.json and reused for subsequent commands.

oras login artifacts.scaleoutsystems.com \
  --username 'robot_<your-robot-account>' \
  --password '<your-token>'

Step 3: Pull the release bundle

Pull the release bundle for your version. Replace vX.Y.Z with the version provided by your Scaleout representative.

oras pull artifacts.scaleoutsystems.com/scaleout/scaleout:vX.Y.Z

This writes a scaleout-vX.Y.Z.tar.gz tarball into a dist/ directory. Change into it and extract:

cd dist
tar -xzf scaleout-vX.Y.Z.tar.gz
cd scaleout-vX.Y.Z/

To check the installed version and list all available versions on the registry, use the bundled update-bundle.sh helper (this requires an existing deployment — see Upgrading once installed):

bash deploy/update-bundle.sh \
  -u 'robot_<your-robot-account>' \
  -p '<your-token>' \
  --check

Deployment Option A: Compose (on-premise or own server)

Use this path when you have a Linux server or VM that you manage directly.

Authenticate to the container registry

The compose deployment pulls pre-built images from Harbor. Log in with Docker using the same credentials:

docker login artifacts.scaleoutsystems.com \
  --username 'robot_<your-robot-account>' \
  --password '<your-token>'

Generate runtime configuration

./deploy/setup.sh <hostname> [OPTIONS]

Replace <hostname> with the domain or IP address where Scaleout will be reachable (e.g. scaleout.mycompany.com or 192.168.1.100).

Common options:

Option

Description

--enable-https

Use https:// URLs (TLS terminated externally, e.g. by a load balancer or reverse proxy)

--enable-tls

Terminate TLS in nginx using certs from runtime/certs/ (implies --enable-https)

--self-signed

Generate a self-signed cert for local HTTPS testing (implies --enable-tls)

--disable-signup

Prevent new users from self-registering

--google-client-id / --google-client-secret

Enable Google OAuth

--microsoft-client-id / --microsoft-client-secret

Enable Microsoft OAuth

See DNS and TLS certificates for when to pick each HTTPS option. Run ./deploy/setup.sh --help for the full option list.

Start services

./deploy/compose.sh up

The platform is accessible at http://<hostname> once all containers are healthy.

See DNS and TLS certificates for how to point a domain at the deployment and serve traffic over HTTPS with your own certificates.

Upgrading

In-place upgrades are handled by deploy/update-bundle.sh. The script stops services, backs up the current bundle, pulls the new release from Harbor, restores runtime/ (secrets and generated config), and starts services again.

Run from inside the existing bundle directory. First check the installed version against what is available on the registry:

sudo bash deploy/update-bundle.sh \
  -u 'robot_<your-robot-account>' \
  -p '<your-token>' \
  --check

To upgrade to the latest available version, drop --check:

sudo bash deploy/update-bundle.sh \
  -u 'robot_<your-robot-account>' \
  -p '<your-token>'

To target a specific version, pass -b:

sudo bash deploy/update-bundle.sh \
  -u 'robot_<your-robot-account>' \
  -p '<your-token>' \
  -b artifacts.scaleoutsystems.com/scaleout/scaleout:vX.Y.Z

A timestamped scaleout-backup-<version>-<date>.tar.gz is written to the parent directory before any files are touched, so the previous bundle can be restored if needed.


Deployment Option B: Cloud (AWS or GCP via Terraform)

Use this path to provision a cloud VM automatically. The Terraform scripts are included in the release bundle under infrastructure/.

The VM bootstraps itself: Terraform creates the instance and passes a startup script that pulls the release bundle from Harbor and runs the deployment — no manual SSH required.

Cloud provider prerequisites

Before running Terraform, the cloud provider CLI must be installed and authenticated on your workstation. Terraform uses the credentials configured by the CLI to call the provider’s APIs.

  • GCP
  • AWS
# Install: https://cloud.google.com/sdk/docs/install
gcloud auth application-default login
gcloud config set project <your-gcp-project-id>
# Install: https://aws.amazon.com/cli/
aws configure

The account used by Terraform needs permission to create and manage a VM, its disk, network resources, and (optionally) snapshot schedules. Minimum required permissions:

GCP — the simplest path is to grant your account the Compute Admin and Service Account User roles on the target project. For a least-privilege setup, grant the equivalent compute.instances.*, compute.disks.*, compute.networks.*, compute.firewalls.*, compute.addresses.*, compute.resourcePolicies.* (only if enable_disk_snapshots = true), and iam.serviceAccounts.actAs permissions. The project must also have billing enabled and the Compute Engine API enabled.

AWS — the account needs permissions on EC2 (instances, key pairs, security groups), VPC (VPCs, subnets, route tables, internet gateways — only if create_vpc = true), and IAM + DLM (only if enable_disk_snapshots = true). The AWS-managed policies AmazonEC2FullAccess and AmazonVPCFullAccess cover the common case; add IAMFullAccess and AWSDataLifecycleManagerFullAccess if snapshots are enabled.

Configure your deployment

Copy the example variables file for your cloud provider and fill in your values:

  • GCP
  • AWS
cd infrastructure/gcp/
cp terraform.tfvars.example terraform.tfvars
cd infrastructure/aws/
cp terraform.tfvars.example terraform.tfvars

Open terraform.tfvars and set at minimum:

  • GCP
  • AWS
project_id      = "your-gcp-project-id"
region          = "us-central1"
zone            = "us-central1-a"
domain          = "scaleout.mycompany.com"
harbor_username = "robot_<your-robot-account>"
harbor_password = "<your-token>"
region          = "eu-north-1"
domain          = "scaleout.mycompany.com"
harbor_username = "robot_<your-robot-account>"
harbor_password = "<your-token>"

release_bundle_ref is pre-filled with the correct version. Replace the Harbor credential placeholders with the values provided by your Scaleout representative.

Terraform variables reference

The tables below cover the variables most customers will need to touch. See terraform.tfvars.example for the full list of optional settings (OAuth providers, HTTPS, SSH access, system admin bootstrap, snapshot scheduling).

Common variables (both providers)

Variable

Description

Default

domain

Hostname where Scaleout will be reachable

(required)

deployment_name

Unique name used as a suffix on cloud resources

default

release_bundle_ref

Full OCI reference to the release bundle on Harbor

pre-filled

harbor_username

Harbor robot account username

(required)

harbor_password

Harbor robot account password / token

(required)

enable_https

Use https:// URLs and secure cookies (requires valid certs)

false

disable_signup

Prevent new users from self-registering

false

google_client_id / google_client_secret

Enable Google OAuth2 login

""

microsoft_client_id / microsoft_client_secret

Enable Microsoft OAuth2 login

""

system_admin_email / system_admin_name / system_admin_password

Bootstrap an initial system admin user

""

ssh_public_key

SSH public key authorised on the VM

""

allowed_ips / ssh_allowed_ips

CIDR ranges permitted to reach the app / SSH

["0.0.0.0/0"]

enable_disk_snapshots

Take daily snapshots of the boot disk

false

snapshot_retention_days

Number of daily snapshots to retain

7

GCP-specific

Variable

Description

Default

project_id

GCP project ID

(required)

region

GCP region

us-central1

zone

GCP zone

us-central1-a

machine_type

VM machine type

e2-standard-4

disk_size_gb

Boot disk size in GB

50

recovery_snapshot

Snapshot name to restore the VM from

""

AWS-specific

Variable

Description

Default

region

AWS region

us-east-1

instance_type

EC2 instance type

t3.xlarge

disk_size_gb

Root volume size in GB

50

create_vpc

Create a new VPC for the deployment

true

vpc_cidr

CIDR for the new VPC

10.0.0.0/16

Apply

Initialise the working directory, review what Terraform is about to create, then apply:

terraform init
terraform plan
terraform apply

Running terraform plan first lets you confirm the resources, regions, and instance sizes before any cloud charges accrue. Terraform then provisions the VM, waits for the startup script to complete, and prints the application URL when done.

See DNS and TLS certificates for how to point your domain at the VM and (optionally) replace the default certificates.

Monitoring startup and troubleshooting

The startup script runs after the VM is created and typically takes 10–15 minutes on first boot (image pull and initial container creation). To follow progress, SSH into the VM and tail the startup logs:

  • GCP
  • AWS
gcloud compute ssh scaleout-vm-<deployment-name> \
    --zone=<zone> --project=<project-id>

sudo journalctl -u google-startup-scripts.service -f
ssh ubuntu@$(terraform output -raw public_ip)

sudo tail -f /var/log/cloud-init-output.log

The script writes /tmp/scaleout-startup-complete when finished. Check the running containers from the deployment directory:

cd /opt/scaleout
./deploy/compose.sh ps
./deploy/compose.sh logs -f

Common checks if something looks wrong:

# Docker is installed and running
docker --version
docker compose version
sudo systemctl status docker

# The release bundle was unpacked
ls -la /opt/scaleout

# DNS resolves to the VM
nslookup <your-domain>

DNS propagation can take 5–60 minutes depending on TTL.

Private network deployment (AWS, no public IP)

If your environment does not permit a public IP on the VM — for example because you reach AWS through a Transit Gateway, Site-to-Site VPN, or Direct Connect — set the following in terraform.tfvars to skip the Elastic IP and launch the VM in a private subnet you already operate:

assign_public_ip = false
create_vpc       = false
vpc_id           = "vpc-xxxxxxxx"
subnet_id        = "subnet-xxxxxxxx"   # must be a private subnet
allowed_ips      = ["10.0.0.0/8"]       # internal CIDRs that may reach the application
ssh_allowed_ips  = ["10.0.0.0/8"]       # internal CIDRs that may SSH into the VM

Prerequisites you (the customer) must provide:

  • A VPC and a private subnet to host the VM, in the AWS region you chose.

  • Outbound internet from that subnet (typically a NAT Gateway or a forward HTTP proxy), so the VM can pull container images from harbor.scaleoutsystems.com, GitHub, Ubuntu/Docker apt repositories, and any configured OAuth identity provider endpoints during provisioning and at runtime.

  • An internal DNS A record for domain pointing at the VM’s private IP. Terraform prints the private IP and the required DNS record in its output after apply.

  • A path for administrative access — VPN, bastion host, or AWS Systems Manager Session Manager — since SSH is reachable only from inside your network.

Upgrading

Upgrading the release bundle is not done through Terraform. Bumping release_bundle_ref and re-running terraform apply only takes effect on a fresh VM. To upgrade an existing deployment, SSH into the VM and run update-bundle.sh exactly as in Option A — the release bundle is installed at /opt/scaleout:

  • GCP
  • AWS
gcloud compute ssh scaleout-vm-<deployment-name> \
    --zone=<zone> --project=<project-id>

cd /opt/scaleout
sudo bash deploy/update-bundle.sh \
    -u 'robot_<your-robot-account>' \
    -p '<your-token>' \
    --check
ssh ubuntu@$(terraform output -raw public_ip)

cd /opt/scaleout
sudo bash deploy/update-bundle.sh \
    -u 'robot_<your-robot-account>' \
    -p '<your-token>' \
    --check

Drop --check to perform the upgrade, or pass -b artifacts.scaleoutsystems.com/scaleout/scaleout:vX.Y.Z to target a specific version. The script preserves runtime/ (secrets and generated config) and writes a timestamped backup to the parent of /opt/scaleout before unpacking the new bundle. See Upgrading for the full command reference.

After upgrading, update release_bundle_ref in terraform.tfvars to match the version now running on the VM so future re-creations stay in sync.


DNS and TLS certificates

Both deployment options serve traffic over plain HTTP by default. To use a real domain and HTTPS:

1. Point DNS at the deployment

Create an A record for your domain that points at the deployment’s public IP. For Option B, Terraform prints the address:

terraform output public_ip

For Option A, use the public IP of the host running the compose stack. DNS propagation usually completes within 5–10 minutes for low TTLs.

2. Enable HTTPS

You have two options for TLS termination.

Self-signed certificate (testing only): deploy/setup.sh can generate a self-signed cert and configure nginx to terminate TLS with it. Re-run setup.sh with --self-signed (Option A) or set self_signed = true in terraform.tfvars (Option B). Browsers will warn about the certificate — useful for internal testing, not production.

./deploy/setup.sh <hostname> --self-signed
./deploy/compose.sh up

Bring your own certificate (production): drop a valid certificate and private key into the deployment’s runtime/certs/ directory as server.crt and server.key, then re-run setup with --enable-tls (which expects certs to already be present) and restart the stack:

# Place fullchain certificate and private key in runtime/certs/
cp /path/to/fullchain.pem runtime/certs/server.crt
cp /path/to/privkey.pem   runtime/certs/server.key

./deploy/setup.sh <hostname> --enable-tls
./deploy/compose.sh up

For Option B, the same files live at /opt/scaleout/runtime/certs/ on the VM. Copy your certs into that directory over SSH and re-run runtime/setup-invocation.sh to regenerate the nginx config, then ./deploy/compose.sh up.


Health checks for external load balancers and gateways

If you place an external load balancer or API gateway in front of the deployment, configure it to probe one of the following unauthenticated HTTP endpoints. Both return 200 OK without authentication and are reachable through the built-in nginx reverse proxy.

Endpoint

Service

Notes

/api/v1/health

REST API

Reflects the health of the API server. Reachable through the nginx /api/v1/ proxy. Returns 200 OK with body OK.

/health

Frontend

Returns 200 OK directly. Use this instead of /, which returns a 308 redirect (via the login/session flow) and must not be used as a health probe.

For example, with the deployment reachable at https://scaleout.mycompany.com:

curl -fsS https://scaleout.mycompany.com/api/v1/health   # -> OK
curl -fsS https://scaleout.mycompany.com/health          # -> OK

Note

nginx also answers /healthz itself (without contacting any upstream). That endpoint only confirms that nginx is up — it does not reflect the health of the application services. Use /api/v1/health and /health for application-level checks from external load balancers.

gRPC services

The Controller, Combiner, and Hooks services expose gRPC rather than HTTP, and implement the standard gRPC Health Checking Protocol. HTTP probes will not work against them. Use grpc_health_probe instead, for example:

grpc_health_probe -addr=<host>:<grpc-port>

This is the same mechanism the bundled Docker Compose stack uses for its container health checks.

Connecting clients over gRPC

Edge clients reach the web UI and REST API on ports 80/443, but they connect to each combiner on its own gRPC port (12080, 12082, … — one per combiner). The client uses a TLS (secure) gRPC channel by default, controlled by the SCALEOUT_GRPC_SECURE environment variable rather than the port number.

Whether the combiner endpoint actually speaks TLS depends on how the deployment terminates it:

Deployment

Combiner gRPC

Client setting

--enable-tls / --self-signed

TLS (terminated by nginx on the combiner ports)

SCALEOUT_GRPC_SECURE=true (default)

Default (plain HTTP)

Plaintext (h2c)

SCALEOUT_GRPC_SECURE=false

--enable-https (TLS terminated externally)

Plaintext from nginx, unless your external proxy is also configured to terminate TLS on the combiner ports

false unless the external proxy fronts the combiner ports with TLS

With --enable-tls or --self-signed, nginx terminates TLS on the combiner ports using the same certificate as the web UI and forwards plaintext gRPC to the combiner internally, so no combiner-side certificate is needed.

Self-signed certificates. A secure-by-default client validates the combiner certificate against the system trust store, which rejects self-signed certs. Point the client at the certificate so it can verify the connection:

export SCALEOUT_GRPC_ROOT_CERT_PATH=/path/to/server.crt
scaleout client start --api-url https://<hostname> --token <TOKEN>

This is the server.crt from the deployment’s runtime/certs/ directory. With a publicly-trusted (CA-issued) certificate, leave SCALEOUT_GRPC_ROOT_CERT_PATH unset — the system trust store handles verification.

See Client Environment Variables for the full list of client settings.