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 syncinsidedeploy/providers/AWS/).Terraform outputs available — you must have already run
make initandmake applyindeploy/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
sudoprivileges (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.
Recommended end-to-end (hybrid) flow
The wrapper target full-deploy-hybrid performs the full Central Hub deploy,
provisions the on-prem trust, updates AWS Secrets Manager with the trust’s
keys, and redeploys the hub so the new secret values are loaded:
cd deploy/providers/AWS
make full-deploy-hybrid PROD=<stag|true> \
LOCAL_TRUST_IP=<public-ip> \
[LOCAL_TRUST_SSH_KEY=~/.ssh/trust_key]
If LOCAL_TRUST_IP is omitted, the operator workstation’s public IP is
auto-detected via curl -s https://api.ipify.org. PROD is inherited
from the environment and supports both staging (stag) and production
(true).
After the wrapper exits, you still need to start the trust stack on the host itself:
cd trust
env PROD=<stag|true> make up-local-trust
Then verify the trust is polling: docker logs -f trust-api should show
successful task polls against 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:
Runs the Ansible playbook
deploy/providers/local/site_local_trust.yml, which installs Docker, required system packages, and creates the/opt/flip/directory tree.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.Runs a targeted
terraform applyto 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 |
|---|---|
|
Must match a name in the hub’s |
|
Per-trust secret used on every outbound call to the hub. |
|
Public hub URL the trust polls (e.g.
|
|
Symmetric key shared with the hub for encrypted payloads. |
|
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):
TRUST_NAMESmust include this trust’s name.TRUST_API_KEY_HASHESmust contain the SHA-256 hash of this trust’sTRUST_API_KEY.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? |
|
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 |
SSH key correct? User has |