Deploy a FLIP node on-prem

An on-prem FLIP node runs the trust-side stack (trust-api, imaging-api, data-access-api, FL client, optional XNAT/Orthanc) on an Ubuntu host owned by the Trust. The node polls the Central Hub for tasks over HTTPS — all communication is outbound, no inbound ports are opened. This is the deployment model used when the Trust has direct, governed access to its own OMOP database and PACS. For deployment inside a TRE see Deploy a FLIP node in a TRE; for the Central Hub side see Deploy the Central Hub.

Architecture

          Internet
              │
              ▼
      ┌──────────────────┐
      │   AWS Central     │
      │   Hub             │
      └─▲──────────────▲─┘
        │              │
 polls  │              │  polls
(HTTPS) │              │ (HTTPS)
        │              │
 ┌──────┴───┐    ┌─────┴───────┐
 │ Trust A   │    │ Trust B      │
 │ (AWS EC2) │    │ (on-prem)    │
 └──────────┘    └─────────────┘

Each on-prem Trust host runs the same Docker Compose stack used on cloud trusts. Container ports are not published on the host (the local-trust compose file communicates over the internal Docker network only), so the stack can coexist with the dev compose stack on the same machine without port conflicts.

Service

Container port

Protocol

trust-api

8000

HTTP (polls hub outbound)

imaging-api

8000

HTTP (internal)

data-access-api

8000

HTTP (internal)

fl-client

TCP (outbound to FL server via NLB)

Prerequisites

Operator workstation (the machine you run commands from — typically your laptop):

  • Python 3.12+ and UV.

  • Ansible (installed automatically by uv sync inside deploy/providers/AWS/).

  • Terraform outputs available — you must have already run make init and make apply in deploy/providers/AWS/ (the Central Hub deployment).

  • SSH access to the trust host, if provisioning remotely.

Trust host — an Ubuntu 22.04+ machine (physical or VM) with:

  • A user account with sudo privileges (default: ubuntu).

  • SSH access from the operator workstation (if remote), or local access.

  • Internet connectivity (to pull Docker images and packages).

  • A writable directory for the FLIP application (default /opt/flip).

Central Hub deployed in AWS — required so the trust can resolve the hub URL, fetch the FL participant kit from S3, and so the operator can update the NLB security group with the trust’s public IP. See Deploy the Central Hub.

Provision-only flows

If the Central Hub is already deployed and you only need to add a new on-prem trust, run provisioning directly:

Remote trust host (via SSH):

cd deploy/providers/AWS
make add-local-trust \
  LOCAL_TRUST_IP=<public-ip> \
  LOCAL_TRUST_SSH_KEY=~/.ssh/trust_key

Local trust host (no SSH — provisioning the same machine you’re on):

cd deploy/providers/AWS
read -rsp 'Sudo password: ' ANSIBLE_BECOME_PASS && echo
export ANSIBLE_BECOME_PASS
make add-local-trust LOCAL_TRUST_IP=<public-ip>

In Fish, the prompt-and-export idiom is different:

cd deploy/providers/AWS
set -x ANSIBLE_BECOME_PASS (read -s -P 'Sudo password: ')
make add-local-trust LOCAL_TRUST_IP=<public-ip>

What add-local-trust does:

  1. Runs the Ansible playbook deploy/providers/local/site_local_trust.yml, which installs Docker, required system packages, and creates the /opt/flip/ directory tree.

  2. Downloads the trust’s FL participant kit from S3 and deploys it to /opt/flip/services/<TRUST_NAME>/{startup,local,transfer} on the trust host.

  3. Runs a targeted terraform apply to add the NLB security group rule that allows FL traffic from the trust’s public IP.

Post-provisioning, start the trust stack on the host:

cd trust
env PROD=stag make up-local-trust

Trust authentication

The Central Hub identifies a trust by its API key, not by IP address or hostname — any host with the correct credentials in its .env can act as that trust. The trust’s env must contain:

Variable

Purpose

TRUST_NAME

Must match a name in the hub’s TRUST_NAMES list (e.g. Trust_2).

TRUST_API_KEY

Per-trust secret used on every outbound call to the hub.

CENTRAL_HUB_API_URL

Public hub URL the trust polls (e.g. https://app.flip.aicentre.co.uk).

AES_KEY_BASE64

Symmetric key shared with the hub for encrypted payloads.

TRUST_INTERNAL_SERVICE_KEY

Per-trust shared secret used inside the trust for calls between trust-api / imaging-api / fl-client and imaging-api / data-access-api. Never leaves the trust.

Hub-side prerequisites (must already be in place before the trust can connect):

  1. TRUST_NAMES must include this trust’s name.

  2. TRUST_API_KEY_HASHES must contain the SHA-256 hash of this trust’s TRUST_API_KEY.

  3. The hub must be redeployed so the new secret values are loaded (make deploy-centralhub).

The full-deploy-hybrid wrapper handles key generation and hub redeployment automatically. When using add-local-trust standalone, the keys must already be configured on the hub.

Network requirements

No inbound port forwarding is needed. Trusts poll the hub outbound for tasks, and FL clients connect outbound to the FL server via the NLB. All communication is trust-initiated.

The trust host must be able to make outbound connections to:

  • The Central Hub FLIP API over HTTPS (port 443).

  • The FL Server endpoint over gRPC or HTTP (configurable port; e.g. 8002).

If the trust’s public IP changes (common with residential broadband), update the NLB security group:

TF_VAR_local_trust_public_ip=<new-ip> make -C deploy/providers/AWS plan apply

Troubleshooting

Symptom

Check

Trust not polling hub

Trust stack running? docker ps on the trust host. Check trust-api logs for polling errors.

Connection timed out (FL)

Trust’s public IP changed? Update the NLB security group. Host/router firewall blocking outbound on port 8002?

Firewall blocking outbound

Confirm the host/router firewall allows outbound HTTPS (443) and the FL gRPC port (default 8002).

Ansible Permission denied

SSH key correct? User has sudo? ANSIBLE_BECOME_PASS set if running in local-host mode?