This section describes how to deploy a standalone validator node on a VM or a local machine using Docker Compose. The deployment consists of the validator node along with associated wallet and CNS UIs, and onboards the validator node to the target network. This deployment is useful for:Documentation Index
Fetch the complete documentation index at: https://docs.canton.network/llms.txt
Use this file to discover all available pages before exploring further.
- Application development, where one needs an ephemeral validator that is easy to deploy.
- Production validators, with the following caveats:
- The default deployment is highly insecure. Authentication should be enabled as described in the authentication section.
- There is no support for ingress from outside your machine, nor is there support for TLS. The deployment should be kept local to your machine only and not exposed externally.
- Reliability & scalability: docker-compose will restart containers that crash, and the deployment supports backup&restore as detailed below, but a docker-compose deployment is inherently more limited than a cloud-based Kubernetes one.
- Monitoring: The deployment, as opposed to a Kubernetes-based one, does not include monitoring.
- For production settings, you should aim to keep your validator up and running constantly, in order to avoid losing out on rewards, and avoid issues with catching up on ledger state after significant downtime.
Requirements
-
A linux/MacOS machine with the following:
- docker compose - at least version 2.26.0 or newer
- curl
- jq
- Your machine should either be connected to a VPN that is whitelisted on the network (contact your sponsor SV to obtain access), or have a static egress IP address. In the latter case, please provide that IP address to your sponsor SV to add it to the firewall rules.
- Please download the release artifacts containing the docker-compose files, from here: Download Bundle, and extract the bundle:
HTTP Proxy configuration
If you need to use an HTTP forward proxy for egress in your environment, you need to sethttps.proxyHost and https.proxyPort in JAVA_TOOL_OPTIONS in splice-node/docker-compose/validator/compose.yaml to use the HTTP proxy for outgoing connections. You need to do this for both the validator and the participant services:
your.proxy.host and your_proxy_port with the actual host and port of your HTTP proxy. Proxy authentication is currently not supported.
Bypassing the proxy for specific hosts
Setting
http.nonProxyHosts affects:- The HTTP client used by the CN apps (Validator, Scan, SV, Wallet).
- JDK-level HTTP clients in the same JVM (via the default
ProxySelector). This includes the Auth0 JWK library used by the CN apps and by the Canton participant for JWKS / OIDC discovery, as well as file downloads that usejava.net.HttpURLConnection. - gRPC egress from other components, because gRPC’s Netty transport delegates proxy decisions to the default JDK
ProxySelector.
http.nonProxyHosts to bypass the proxy for specific target hosts. Matching hosts will be contacted directly rather than through the configured proxy. This is useful for services that are reachable on the local network, such as an in-cluster Scan instance or internal monitoring endpoints.
The value is a |-separated list of patterns that follows the standard Java nonProxyHosts grammar:
- Patterns match the request host name case-insensitively.
*is a wildcard. Conventionally it is used at the start (*.internal) or end (10.*) of a pattern.- Matching is performed on the raw host string from the request URI. No DNS resolution is performed, so
localhostand127.0.0.1are treated as different names unless you list both. - An empty value (e.g.
-Dhttp.nonProxyHosts=) means “no bypass patterns”.
validator service but bypasses the proxy for localhost / 127.0.0.1, any host in the .internal domain, and any IPv4 address whose literal string representation starts with 10.:
Deployment
- Change to the
docker-composedirectory inside the extracted bundle:
- Export the current version to an environment variable: export IMAGE_TAG=0.6.3
- Run the following command to start the validator node, and wait for it to become ready (could take a few minutes):
Note that the validator may be stopped with the command
./stop.sh and restarted again with the same start.sh command as above. Its data will be retained between invocations. In subseqent invocations, the secret itself may be left empty, but the -o is still mandatory, so a -o "" argument should be provided.
Logging into the wallet UI
Docker Compose-based validator deployments use
.localhost subdomains for addressing, such as wallet.localhost. .localhost URLs reportedly do not work on some browsers. If you encounter issues please try using a different browser such as Firefox or Chrome. If you’re encountering issues with reaching APIs from a custom program or script, you may need to set the HOST header on HTTP requests explicitly to the target .localhost address.administrator. Insert that name into the username field and click Log in, and you should see the wallet of the administrator of your wallet.
You can also logout of the administrator account and login as any other username. The first time a user logs in, they will be prompted with a message asking them to confirm whether they wish to be onboarded to the validator node.
link to section that explains what this onbarding means
Logging into the CNS UI
You can open your browser at http://ans.localhost (note that this is currently by defaultans and not cns), and login using the same administrator user, or any other user that has been onboarded via the wallet, in order to purchase a CNS entry for that user.
Accessing the Canton Participant APIs
The JSON Ledger API is exposed underjson-ledger-api.localhost:80. Note that for some clients you may explicitly need to set the Host: json-ledger-api.localhost header for this to get resolved correctly.
The gRPC Ledger API is exposed under grpc-ledger-api.localhost:80. Note that for some clients you may explicitly need to set the :authority: json-ledger-api.localhost pseudo-header for this to get resolved correctly.
The Canton Admin API is not exposed by default as it does not yet support auth. There is a commented out section in nginx.conf that you can enable to expose it if you ensure that it is not exposed publicly, e.g., through network restrictions.
Configuring Authentication
Please refer to the authentication section for instructions on how to set up an OAuth provider for your validator. The URLs to configure for callbacks arehttp://wallet.localhost and http://ans.localhost.
Once you have set up your OAuth provider, you need to configure it by setting the following environment variables in the .env file:
| Name | Value |
|---|---|
| AUTH_URL | The URL of your OIDC provider for obtaining the openid-configuration and jwks.json. |
| AUTH_JWKS_URL | The URL of your OIDC provider for obtaining the jwks.json, will typically be $/.well-known/jwks.json. |
| AUTH_WELLKNOWN_URL | The URL of your OIDC provider for obtaining the openid-configuration, will typically be $/.well-known/openid-configuration. |
| |
| |
| VALIDATOR_AUTH_AUDIENCE | The audience for the validator backend API. e.g. https://validator.example.com. |
| VALIDATOR_AUTH_CLIENT_ID | The client id of the OAuth app for the validator app backend. |
| VALIDATOR_AUTH_CLIENT_SECRET | The client secret of the OAuth app for the validator app backend. |
| LEDGER_API_ADMIN_USER | Should match the sub field of JWTs issued for the validator app. For some auth providers, this would be formed as CLIENT_ID@clients. |
| WALLET_ADMIN_USER | The user ID of the user which should login as the wallet administrator. Note that this should be the full user id, e.g., auth0|43b68e1e4978b000cefba352, not only the suffix 43b68e1e4978b000cefba352. |
| WALLET_UI_CLIENT_ID | The client id of the OAuth app for the wallet UI. |
| ANS_UI_CLIENT_ID | The client id of the OAuth app for the CNS UI. |
| CONTACT_POINT | The contact point for your validator node that can be used by other node operators to reach out to you if needed (slack username or an email address). Optional |
-a flag to the start.sh command, as follows:
./stop.sh and restarting it with the -a flag as above. The validator operator user will be automatically migrated, and the user indicated by the WALLET_ADMIN_USER variable will be associated with the validator operator party. If you have also onboarded other users onto your validator, those will not be automatically migrated, and you need to manually associate the OAuth users with their corresponding parties. In order to do that, first take note of the party IDs of all relevant users (do this before stopping the unauthenticated validator), e.g. by copying them from the top-right corner of their wallet UIs. Now for every user that you wish to migrate, follow the instructions for associating a user with a party in the Users, Parties and Wallets in the Splice Wallet section, but replace the admin party ID with the party ID which you wish to associate with each user.
Configuring Automatic Traffic Purchases
Your node is configured to automatically purchase traffic on a pay-as-you-go basis (see automatically purchase traffic). To tune to your needs, you can set environment variables, for example:Configuring sweeps and auto-accepts of transfer offers
To do so, fill the following section and add the following additional config to your validator environment:Integration with systemd and other init systems
If you want to manage the validator through systemd or a similar init system, create a service that calls thestart.sh script with the right arguments. However, note that start.sh invokes docker compose up with the -d/--detach option so the script exits after the containers are up instead of continuing running.
You need to make sure that your service does not stop docker compose at that point. To accomplish this with systemd set RemainAfterExit=true. Refer to the systemd documentation for more details. If you are using another init system, look for similar options to ensure that docker compose continues running after the script exits.
Alternatively, you can edit the script to remove the -d option so the script continues running.