.. _deploy-flip-node-on-prem: ############################### 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 :doc:`deploy-flip-node-in-tre`; for the Central Hub side see :doc:`deploy-central-hub`. .. contents:: On this page :local: :depth: 2 ************ Architecture ************ .. code-block:: text 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 :doc:`deploy-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: .. code-block:: shell cd deploy/providers/AWS make full-deploy-hybrid PROD= \ LOCAL_TRUST_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: .. code-block:: shell cd trust env PROD= 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):** .. code-block:: shell cd deploy/providers/AWS make add-local-trust \ LOCAL_TRUST_IP= \ LOCAL_TRUST_SSH_KEY=~/.ssh/trust_key **Local trust host (no SSH — provisioning the same machine you're on):** .. code-block:: bash cd deploy/providers/AWS read -rsp 'Sudo password: ' ANSIBLE_BECOME_PASS && echo export ANSIBLE_BECOME_PASS make add-local-trust LOCAL_TRUST_IP= In Fish, the prompt-and-export idiom is different: .. code-block:: fish cd deploy/providers/AWS set -x ANSIBLE_BECOME_PASS (read -s -P 'Sudo password: ') make add-local-trust LOCAL_TRUST_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//{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: .. code-block:: shell 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: .. code-block:: shell TF_VAR_local_trust_public_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? | +----------------------------------+------------------------------------------------------------+