Deploy

Deploy the Nuts node and, optionally, Nuts Admin. Put the node behind a reverse proxy with the right TLS certificates, and check that it's reachable.

Deploy the Nuts node

There are two ways to run the Nuts part of your system. Choose one:

Option What it is When to choose it
Nuts node (default) The Nuts node on its own. You build the integration with your EHR yourself, following this book. You want full control, or you already integrate with the Nuts node
Nuts Knooppunt Has an embedded Nuts node, plus components for integrating with the MinVWS Generic Functions (Generieke Functies), such as a policy decision point (PDP) for access decisions and Mitz integration You want more ready-made parts, or you integrate with the Generic Functions. See the Knooppunt section below

One Nuts node per vendor (and per environment) hosts all of the vendor's care organizations.

Nuts node

The Nuts node documentation describes deployment in detail. Start with the recommended deployment and running on Docker.

Install

The Nuts node is published as:

Form Where
Docker image nutsfoundation/nuts-node on Docker Hub
Helm chart, for Kubernetes Helm repository https://nuts-foundation.github.io/nuts-node, chart nuts-node-chart (source)
Binaries (Linux, amd64 and arm64) GitHub releases

Use a fixed version (e.g. nutsfoundation/nuts-node:<version>), not latest. For the latest version, see the GitHub releases. Docker images are signed; see verifying image signatures.

Configuration

The settings you need for a spec v2 use case. Each can be set in nuts.yaml or as an environment variable (NUTS_ + the name in capitals, with _ instead of ., e.g. NUTS_HTTP_INTERNAL_ADDRESS).

Setting Value Why
url Your node's public URL, e.g. https://nuts.example.com Used in your did:web DIDs and OAuth2 URLs. Must be HTTPS.
strictmode true (default) Forbids insecure settings. Only turn it off on development or test systems without production data.
didmethods web Spec v2 only uses did:web (see "Create a subject").
http.internal.address e.g. :8081 The internal API. Default 127.0.0.1:8081, which can't be reached from outside the container.
storage.sql.connection Connection string to PostgreSQL, MySQL or SQL Server (including Azure SQL) The default, SQLite, isn't meant for production.
crypto.storage vaultkv (HashiCorp Vault) or azure-keyvault Where private keys are stored. fs (on disk) is only for development.
discovery.definitions.directory Directory with the Discovery Service definitions See chapter "Configure the node for a use case".
policy.directory Directory with the policy definitions See chapter "Configure the node for a use case".

Network

Check that it works

Nuts Knooppunt

Knooppunt has an embedded Nuts node, so the steps in this book still apply. It also has a policy decision point (PDP) that helps you decide whether to allow an inbound query (see "Validate the access token").

See the Knooppunt documentation, in particular:

Endpoints and TLS certificates

Which endpoints you expose, to whom, and with which TLS certificate. This repeats the recommended deployment for spec v2 use cases; see there for details.

Nuts node endpoints

Your reverse proxy terminates TLS for the public endpoints.

Endpoint Interface Who uses it Protection
/iam Public (:8080) Other parties resolving your did:web DID documents HTTPS with a publicly trusted server certificate
/.well-known Public (:8080) Other parties: DID documents, OAuth2 metadata HTTPS with a publicly trusted server certificate
/oauth2 Public (:8080) Other Nuts nodes requesting access tokens from you HTTPS with a publicly trusted server certificate
/statuslist Public (:8080) Parties checking whether credentials you issued are revoked HTTPS with a publicly trusted server certificate
/discovery Public (:8080) Only if your node runs a Discovery Service server HTTPS with a publicly trusted server certificate
/internal Internal (:8081) Your own applications, Nuts Admin Never public: restrict access through network separation
/status, /status/diagnostics, /health, /metrics Internal (:8081) Monitoring, health checks Restrict access through network separation
/n2n, /public, gRPC (:5555) — Spec v1 (did:nuts) only Don't expose them

Your data endpoints

Protect your FHIR API (or other data API) with mutual TLS (mTLS) based on PKIoverheid certificates: both your server and the calling vendor's client authenticate with a PKIoverheid certificate. Check the use case's IG for what's allowed in test environments.

Don't mix up the certificates

Certificate Used for
UZI server certificate Creating the care organization's X509Credential (see "Get an X509Credential from a UZI certificate")
Publicly trusted TLS certificate The Nuts node's public endpoints
PKIoverheid certificate mTLS on your data endpoints

Deploy admin app

Nuts Admin is an optional web application for managing your Nuts node by hand: create subjects, load and issue credentials, and register on Discovery Services. It's useful for testing and for small numbers of care organizations. For many care organizations, integrate with the node's internal API instead, as described in the rest of this book.

Run it

docker run -p 1305:1305 -e NUTS_NODE_ADDRESS=http://nutsnode:8081 nutsfoundation/nuts-admin:<version>

See the Nuts Admin README for all settings.

Secure it

Nuts Admin passes requests on to the node's internal API. Anyone who can reach Nuts Admin can manage your node.

Never expose Nuts Admin to the internet without login.

Configure url rewrite for OAuth

Other parties look up your node's OAuth2 metadata at a .well-known URL, which always starts at the root of the domain (RFC 8615). If your node runs at the root of its own (sub)domain, e.g. https://nuts.example.com, you don't need to do anything.

If the node runs on a subpath, e.g. https://example.com/nuts, your reverse proxy must forward the OAuth2 metadata URL to the node. Example for a node on /nuts:

Other parties request Forward to the node as
https://example.com/.well-known/oauth-authorization-server/nuts/oauth2/<subject ID> /.well-known/oauth-authorization-server/oauth2/<subject ID>

In short: remove the subpath (/nuts) after the .well-known/... part.

The node serves all its other endpoints at the root too (/iam, /oauth2, /statuslist, ...). So your proxy must also remove /nuts from those, e.g. forward https://example.com/nuts/oauth2/... to /oauth2/....

NGINX

location /.well-known/oauth-authorization-server/nuts/ {
    proxy_pass http://nuts-node:8080/.well-known/oauth-authorization-server/;
}

Azure Application Gateway

path: '/.well-known/oauth-authorization-server/nuts'
rewriteCondition: '/.well-known/oauth-authorization-server/nuts(.*)'
rewriteRule: '/.well-known/oauth-authorization-server{var_uri_path_1}'

Check that it works

From outside your network, open:

https://example.com/.well-known/oauth-authorization-server/nuts/oauth2/<subject ID>

It should return JSON with your node's OAuth2 metadata, e.g. an issuer of https://example.com/nuts/oauth2/<subject ID>.