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.
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 |
|---|---|
|
Use |
|
Terminate TLS in nginx using certs from |
|
Generate a self-signed cert for local HTTPS testing (implies |
|
Prevent new users from self-registering |
|
Enable Google OAuth |
|
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.
# 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:
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:
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 |
|---|---|---|
|
Hostname where Scaleout will be reachable |
(required) |
|
Unique name used as a suffix on cloud resources |
|
|
Full OCI reference to the release bundle on Harbor |
pre-filled |
|
Harbor robot account username |
(required) |
|
Harbor robot account password / token |
(required) |
|
Use |
|
|
Prevent new users from self-registering |
|
|
Enable Google OAuth2 login |
|
|
Enable Microsoft OAuth2 login |
|
|
Bootstrap an initial system admin user |
|
|
SSH public key authorised on the VM |
|
|
CIDR ranges permitted to reach the app / SSH |
|
|
Take daily snapshots of the boot disk |
|
|
Number of daily snapshots to retain |
|
GCP-specific
Variable |
Description |
Default |
|---|---|---|
|
GCP project ID |
(required) |
|
GCP region |
|
|
GCP zone |
|
|
VM machine type |
|
|
Boot disk size in GB |
|
|
Snapshot name to restore the VM from |
|
AWS-specific
Variable |
Description |
Default |
|---|---|---|
|
AWS region |
|
|
EC2 instance type |
|
|
Root volume size in GB |
|
|
Create a new VPC for the deployment |
|
|
CIDR for the new VPC |
|
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:
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
domainpointing 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:
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 |
|---|---|---|
|
REST API |
Reflects the health of the API server. Reachable through the nginx |
|
Frontend |
Returns |
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 |
|---|---|---|
|
TLS (terminated by nginx on the combiner ports) |
|
Default (plain HTTP) |
Plaintext (h2c) |
|
|
Plaintext from nginx, unless your external proxy is also configured to terminate TLS on the combiner ports |
|
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.