> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dfns.co/llms.txt
> Use this file to discover all available pages before exploring further.

# MPC signer deployment runbook

> Step-by-step operational runbook for deploying, configuring, and managing DFNS MPC signer nodes on your own cloud or hybrid infrastructure.

export const SupportLink = ({children}) => {
  const url = "https://support.dfns.co";
  return <a href={url} target="_blank">{children || url}</a>;
};

This runbook provides the detailed steps to deploy DFNS MPC signers on your own infrastructure. For an overview of MPC architecture, key generation and signing flows, and threshold schemes, see the [MPC signing infrastructure](/advanced/deployment-models/mpc) page.

## Prerequisites

Before starting the deployment, ensure the following are in place:

* **Infrastructure**: Compute resources capable of running containerized workloads (Kubernetes preferred) or standalone containers/binaries. Supported environments:
  * **Public cloud**: AWS EKS, GCP GKE, or self-managed Kubernetes
  * **Private cloud / data center**: Custom environments are supported. We recommend collaborating with DFNS infrastructure teams on a design document for highly custom environments.
* **Database**: A PostgreSQL instance (recommended) or equivalent SQL database, accessible from all signer hosts.
* **Secrets management**: A solution for storing encryption keys used to protect key shares at rest (e.g. AWS Secrets Manager).
* **Networking**: The DFNS backend initiates connections to your signers, so they must be reachable on their configured DNS domains. Signers also need outbound connectivity to the delivery server. See the [networking step](#configure-networking) below for details on IP allowlisting.
* **Senior infrastructure engineer**: We strongly recommend assigning a senior infrastructure engineer to lead the project. You may also want to involve your security team.

## Implementation steps

<Steps>
  <Step title="Provision infrastructure">
    Set up the compute environment where signers will run. Technical requirements depend on the load (number of signatures). As a starting point: 4 CPU cores with 512MB of RAM per signer.

    The DFNS stack is cloud-agnostic. Deploy using managed Kubernetes (AWS EKS, GCP GKE), container services (AWS ECS), or standalone containers/binaries. If you are not using Kubernetes, each container can also be deployed independently.

    For proprietary data centers (third-party hosted or internally managed), environments tend to be highly custom. We recommend having our infrastructure teams collaborate on a design document detailing the specific constraints of your environment.
  </Step>

  <Step title="Set up databases for key share persistence">
    Each signer persists its encrypted key shares in its own database instance.

    * We recommend **PostgreSQL** and using it is the shortest path to deployment.
    * Alternative SQL databases are supported via the generic ORM engine. Contact our <SupportLink>Support Team</SupportLink> before using a non-PostgreSQL database to confirm compatibility.
    * Performance matters: the faster the storage and retrieval of key shares, the better your signing performance will be.
    * Ensure each database is backed up regularly.
  </Step>

  <Step title="Obtain signer software from DFNS">
    DFNS provides the signer as a **Docker container image** via Amazon ECR. To get access, provide DFNS with:

    * Your **AWS account ID** (for ECR image pull access)
    * A **GitHub account** (for access to the deployment scripts repository)

    DFNS will grant access and share the latest image tag and repository details.
  </Step>

  <Step title="Set up mTLS certificates">
    The signers use mTLS to establish secure communication channels with the DFNS API. Each signer requires **two sets of certificates**:

    1. **API certificates**: for communication between the DFNS API (client) and the signer (server).
    2. **Delivery server certificates**: for inter-signer communication through the delivery server.

    <Note>
      If your deployment is hybrid and DFNS hosts some signers, you do not need to host the delivery server.
    </Note>

    ```mermaid theme={null}
    sequenceDiagram
        participant Customer
        participant DFNS

        DFNS->>Customer: 1. Provide CSR template
        Customer->>Customer: 2. Generate key pair + CSR per signer
        Customer->>DFNS: 3. Send CSRs
        DFNS-->>Customer: Signed certificates
        Customer->>Customer: 4. Install cert + private key on each signer
    ```

    **Certificate setup procedure:**

    1. **DFNS provides the signer repository**: the repository contains a helper script at `scripts/generate-csr.sh`.
    2. **You generate a CSR for each signer**: run the script once per signer. You can assign your own domains (e.g. `signer-0.customer.xyz`, `signer-1.customer.xyz`).

    ```bash theme={null}
    # Set your organization details
    export COUNTRY_CODE="US"
    export STATE="California"
    export LOCALITY="San Francisco"
    export ORGANIZATION="Your Company"
    export ORGANIZATION_UNIT="Engineering"
    export DOMAIN="customer.xyz"
    export EMAIL_ADDRESS="security@customer.xyz"

    # Run once per signer
    ./scripts/generate-csr.sh signer-0
    ./scripts/generate-csr.sh signer-1
    ```

    This generates a private key (`signer-0-key.pem`) and a CSR (`signer-0.csr`) for each signer, with the domain set to `signer-0.customer.xyz`.

    3. **You send each CSR to DFNS**: DFNS signs them and returns a valid certificate for each signer.
    4. **You install certificates on each signer**: inject the certificate and corresponding private key into each signer.

    <Warning>
      The DFNS backend connects to your signers directly. They must be publicly reachable on the DNS domains you specified in the CSRs.
    </Warning>
  </Step>

  <Step title="Configure networking">
    The DFNS backend initiates inbound connections to your signers for key generation and signing ceremonies. Your signers also need outbound connectivity to the delivery server.

    **Inbound (DFNS to your signers):** allow inbound traffic from the DFNS outbound IP for your region. These IPs are listed on the [DFNS regions page](/api-reference/regions). Provide DFNS with your signer egress IPs so they can be allowlisted on the DFNS side.

    **Outbound (your signers to DFNS):** signers need outbound HTTPS access to the delivery server and DFNS API endpoints.

    <Note>
      If your security policy requires it, restrict outbound traffic to DFNS endpoints only. Contact our <SupportLink>Support Team</SupportLink> for the exact list of endpoints.
    </Note>
  </Step>

  <Step title="Configure and deploy signers">
    The signer binary is `dfns-signer-cli` (also available as a Docker container image).

    **Core keys pack.** Each signer needs a core keys pack containing three randomly-generated keys: an identity key, an obfuscation key, and a decryption key. The decryption key is the key used to encrypt all key shares at rest (in the database and in `s3-backup`).

    These keys are generated locally on your infrastructure (DFNS never holds them). The DFNS Helm chart automates this via a bootstrap job: an init container runs `dfns-signer-cli make-pack signer-core-keys` to generate the pack, then a provider-specific script (AWS, GCP) stores it in your secrets manager. On every subsequent signer start, an init container reads the pack back from the secrets manager and writes it to a shared volume for the signer to consume. If you deploy without the Helm chart, you must replicate this flow.

    <Warning>
      Losing the decryption key makes every wallet unrecoverable unless [Layer 4](#set-up-layer-4-disaster-recovery-optional) is enabled. Make sure your secrets manager has backup and replication configured.
    </Warning>

    **Start each signer** with:

    ```bash theme={null}
    dfns-signer-cli start signer \
      --secret-core-keys-pack /path/to/core-keys.json \
      --tls-secret-keys-pack /path/to/tls-keys.json \
      --listen-at 0.0.0.0:8700 \
      --health-listen-at 0.0.0.0:3490 \
      --secrets-manager-type postgres \
      --postgres-url postgres://user:pass@db:5432/signer_db \
      --store-provision-at secrets-manager \
      --s3-backup-bucket-name my-backup-bucket \
      --s3-backup-bucket-region us-east-1 \
      --s3-backup-prefix signer-0/
    ```

    | Flag                        | Description                                                                              |
    | --------------------------- | ---------------------------------------------------------------------------------------- |
    | `--secret-core-keys-pack`   | Path to the core keys pack. Typically materialized at startup from your secrets manager. |
    | `--tls-secret-keys-pack`    | Path to the TLS keys pack (mTLS certificates from the previous step).                    |
    | `--listen-at`               | Address and port for the gRPC server (must be reachable by the DFNS API).                |
    | `--health-listen-at`        | Address and port for the health check endpoint.                                          |
    | `--secrets-manager-type`    | Key share storage backend. Use `postgres`.                                               |
    | `--postgres-url`            | PostgreSQL connection string for key share storage.                                      |
    | `--store-provision-at`      | Where to store provisioning data. Use `secrets-manager`.                                 |
    | `--s3-backup-bucket-name`   | S3 bucket for key share backups (recommended).                                           |
    | `--s3-backup-bucket-region` | AWS region of the backup bucket.                                                         |
    | `--s3-backup-prefix`        | Per-signer prefix in the bucket (e.g. `signer-0/`).                                      |

    <Note>
      The `--s3-backup-*` flags configure your **Layer 3** backup: the same ciphertext stored in the database, encrypted with the decryption key from your core keys pack, copied to an S3 bucket. It is not an independent recovery path, since restoring from it still requires the original core keys pack, but it lets you [rebuild a signer](/advanced/deployment-models/L3-disaster-recovery) if its database is lost. For a fully independent path with a customer-supplied encryption key, see [Layer 4](#set-up-layer-4-disaster-recovery-optional).
    </Note>

    <Note>
      Threshold parameters (e.g. 3-of-5) are not part of the signer configuration. They are set during key generation ceremonies orchestrated by the DFNS API.
    </Note>

    Deploy using your chosen method (Kubernetes, Docker, ECS, or standalone binary). Once started, the DFNS API will connect to the signers over mTLS and orchestrate ceremonies. Verify the integration by creating a test wallet through the DFNS API and confirming it completes successfully.
  </Step>

  <Step title="Deploy the full signer quorum">
    All signers in the threshold scheme must be deployed. Key generation (DKG) requires every signer to participate. For a 3-of-5 configuration:

    * Deploy all 5 signer instances, ideally across different availability zones or physical locations.
    * All signers must participate in key generation ceremonies. Once keys are generated, only 3 of the 5 need to be available for signing.
    * The system can tolerate 2 signer failures during signing without service interruption.
    * All signers must have access to their respective database and encrypted key shares.
  </Step>
</Steps>

## Configure validation gate (optional)

The [validation gate](/advanced/deployment-models/validation-gate) adds a pre-signing authorization step where your HTTP handler approves or rejects every transaction before the signer proceeds.

### Configuration

Enable the validation gate by providing the target URL when starting the signer.

| Parameter                       | Environment variable          | Description                                                                                 |
| :------------------------------ | :---------------------------- | :------------------------------------------------------------------------------------------ |
| `--validation-gate-url`         | `VALIDATION_GATE_URL`         | URL of your validation gate handler. Setting this enables the feature.                      |
| `--validation-gate-secret`      | `VALIDATION_GATE_SECRET`      | Hex-encoded 32-byte shared secret for HMAC request signing. Optional.                       |
| `--validation-gate-disable-tls` | `VALIDATION_GATE_DISABLE_TLS` | Disable TLS for the connection to the validation gate server. Optional, default is `false`. |

<Note>
  Validation gate cannot be used with CGGMP24 pre-signatures. If this need arises, contact our <SupportLink>Support Team</SupportLink>.
</Note>

### HMAC shared secret

When a shared secret is configured, the signer signs the JSON request body using HMAC-SHA256 and includes the signature in the HTTP headers. Your handler can use this to verify that requests are genuinely coming from the signer:

| Header                     | Value                                                    |
| :------------------------- | :------------------------------------------------------- |
| `x-payload-signature-type` | `hmac-sha256`                                            |
| `x-payload-signature`      | Base64-encoded HMAC-SHA256 signature of the request body |

Your handler should recompute the HMAC over the raw request body using the same shared secret and compare it to the value in `x-payload-signature`.

### mTLS

The signer can connect to your validation gate server using mutual TLS with a dedicated client certificate.

To enable mTLS, add the following fields in the signer's TLS keys pack:

* `validation_gate_tls_client_key`: PEM-encoded TLS client key
* `validation_gate_tls_client_cert`: PEM-encoded TLS client cert
* `validation_gate_tls_server_ca`: PEM-encoded CA certificate of your server

If there is no need for TLS (e.g. your validation gate is on the same server as the signer), use the `--validation-gate-disable-tls` flag.

## Set up Layer 4 disaster recovery (optional)

[Layer 4 disaster recovery](/advanced/deployment-models/disaster-recovery#layer-4-disaster-recovery) automatically encrypts each key share with your Ed25519 public key during wallet creation and stores the encrypted backup in an S3 bucket you own.

### Setup

<Steps>
  <Step title="Generate an Ed25519 key pair">
    Generate an Ed25519 key pair. The private key is your recovery key. You can use a single key pair across all signers (most common) or generate one per signer.

    ```bash theme={null}
    # Generate private key
    openssl genpkey -algorithm ed25519 -out l4_private_key.pem

    # Extract public key
    openssl pkey -in l4_private_key.pem -pubout -out l4_public_key.pem
    ```

    Alternatively, generate the key in a KMS (e.g. AWS KMS, Azure Key Vault, GCP Cloud KMS) and export only the public key.

    <Warning>
      Losing the private key means losing the ability to recover from Layer 4 backups. Store it offline in a physically secure location with multiple copies in separate locations. If using a KMS, ensure the key is non-deletable and replicated.
    </Warning>
  </Step>

  <Step title="Create an S3 bucket">
    Create an S3 bucket in your AWS account to hold the encrypted backups. Recommended configuration:

    | Setting                      | Recommendation                                                                                          |
    | ---------------------------- | ------------------------------------------------------------------------------------------------------- |
    | **Versioning**               | Enabled. Protects against accidental overwrites.                                                        |
    | **Access control**           | Restrict access to authorized personnel only. DFNS signers need `s3:PutObject` (write-only) permission. |
    | **Server-side encryption**   | Enabled. Adds a layer of protection on top of the public-key encryption already applied to each share.  |
    | **Cross-region replication** | Recommended for additional durability.                                                                  |
  </Step>

  <Step title="Provide configuration to DFNS">
    If DFNS hosts some or all of your signers, send them:

    * **Public key**: your Ed25519 public key in PEM format (contents of `l4_public_key.pem`)
    * **Bucket name**: your S3 bucket name (e.g. `my-org-l4-backups`)
    * **Bucket region**: the AWS region where the bucket is located (e.g. `us-east-1`)

    DFNS will configure the signers it hosts and provide the IAM role ARNs that need write access so you can update your bucket policy.
  </Step>

  <Step title="Configure self-hosted signers">
    If you host signers yourself, add the following flags:

    | Flag                        | Description                                         |
    | --------------------------- | --------------------------------------------------- |
    | `--l4-backup-bucket-name`   | Your S3 bucket name                                 |
    | `--l4-backup-bucket-region` | The AWS region of the bucket                        |
    | `--l4-backup-prefix`        | Prefix for this signer's backups (e.g. `signer-0/`) |
    | `--l4-backup-pubkey`        | Path to your Ed25519 public key in PEM format       |
  </Step>

  <Step title="Verify">
    Create a test wallet through the DFNS API and verify that encrypted backup files appear in your S3 bucket under each signer's prefix.
  </Step>
</Steps>

### Layer 4 recovery

To decrypt and assemble private keys from your Layer 4 backups, follow the [Layer 4 disaster recovery runbook](/advanced/deployment-models/L4-disaster-recovery). The procedure is entirely independent of DFNS.

## Responsibility matrix (RACI)

<Note>
  This matrix is based on the standard deployment. Discuss any adjustments with your DFNS contact for your specific deployment.
</Note>

* **R** = Responsible (does the work)
* **A** = Accountable (owns the outcome)
* **C** = Consulted (provides input)
* **I** = Informed (kept up to date)

| Activity                                            | Customer | DFNS |
| --------------------------------------------------- | :------: | :--: |
| Infrastructure provisioning (compute, network)      |    R/A   |   C  |
| Database provisioning and management                |    R/A   |   C  |
| Database backup and disaster recovery               |    R/A   |   —  |
| Secrets management (encryption keys)                |    R/A   |   —  |
| Signer software delivery                            |     I    |  R/A |
| mTLS CSR template                                   |     I    |  R/A |
| CSR generation (per signer)                         |    R/A   |   —  |
| Certificate signing                                 |     I    |  R/A |
| Certificate installation on signers                 |    R/A   |   C  |
| Signer deployment and configuration                 |    R/A   |   C  |
| Signer software updates                             |     R    |   A  |
| Delivery server (hybrid: DFNS-hosted)               |     —    |  R/A |
| Delivery server (full on-premise)                   |    R/A   |   C  |
| DNS configuration for signer domains                |    R/A   |   —  |
| DFNS API availability and maintenance               |     —    |  R/A |
| Network connectivity (signers to internet)          |    R/A   |   —  |
| End-to-end integration testing                      |     R    |   C  |
| Ongoing signer administration                       |    R/A   |   C  |
| Incident response (infrastructure / network)        |    R/A   |   C  |
| Incident response (DFNS API / signer software bugs) |     C    |  R/A |

## Backup and disaster recovery

For a complete overview of what to back up and recovery scenarios, see the [disaster recovery](/advanced/deployment-models/disaster-recovery) page.

Key takeaways:

* **Encryption keys** are the most critical asset. Loss without [Layer 4](/advanced/deployment-models/disaster-recovery#layer-4-disaster-recovery) is unrecoverable.
* **Database backups** should be taken regularly. Any key shares created after the last backup are lost if the database fails.
* **Layer 3 backup** (the `s3-backup`) lets you rebuild a signer if its database is lost, using the [Layer 3 disaster recovery runbook](/advanced/deployment-models/L3-disaster-recovery).
* **Layer 4 backups** (if enabled) are stored in your own S3 bucket and provide an independent recovery path via the [Layer 4 disaster recovery runbook](/advanced/deployment-models/L4-disaster-recovery).

## Security considerations

* **mTLS authentication**: All communication between signers and the DFNS API (and between signers via the delivery server) is encrypted and mutually authenticated.
* **Encrypted key shares**: Key shares are always encrypted at rest and in transit. When hosting signers on-premise, you manage the encryption keys.
* **No single point of compromise**: MPC ensures no single signer holds the complete private key. An attacker must compromise the threshold number of signers.
* **Customer-controlled infrastructure**: You retain full control over the compute, network, database, and encryption keys, enabling compliance with your internal security policies.

## Estimated timeline

While timelines vary based on deployment parameters, a general schedule targets concept to launch within one month:

| Week | Activities                                                                       |
| ---- | -------------------------------------------------------------------------------- |
| 1    | Meet to discuss specific requirements, document them in a shared design document |
| 2    | Set up security certificates, begin deployment of testnet environment signers    |
| 3    | Complete testing on testnet, adjust based on results, plan production deployment |
| 4    | Complete production deployment and testing                                       |
| 5    | Go live                                                                          |

## Contact

For questions about on-premise signer deployment or to begin the integration process, contact our <SupportLink>Support Team</SupportLink>.
