Skip to main content

Running the Server

You need the docker compose that runs both auth-svc and duo-server, as well as the .env file with your credentials. Additionally you need the signing key for duo-server.

two-party-boilerplate-backend/
├── docker-compose.hooks.with-duo-server.yml # runs auth-svc + duo-server
|── testdata/
| └── party_0_sk # duo-server signing key
└── .env

1. Prepare the files needed to run the server:

If you have access to the auth-svc repository, you can can skip this section.

You need to create the docker-compose file, the .env file, and generate a signing key for duo-server. Follow the instructions below to prepare these files.

Save docker compose file:

docker-compose.hooks.with-duo-server.yml

# docker-compose.yml
version: "3.9"

networks:
duo-net:
driver: bridge
services:
duo-server:
image: "ghcr.io/silence-laboratories/dkls23-rs/duo-server:v6.3.0"
container_name: duo-server
command: /usr/local/bin/sigpair-node
environment:
RUST_LOG: "info"
LISTEN: "0.0.0.0:8080"
DEV_MASTER_SIGN_KEY: /run/secrets/duo-signing-master-key
FILE_STORAGE_URL: "file:///data/"
# Auth hooks configuration
AUTH_HOOK_TYPE: "webhook"
AUTH_DKG_SETUP_VALIDATOR_URL: "http://auth-svc:9090/hook/dkg_setup_validation"
AUTH_DSG_SETUP_VALIDATOR_URL: "http://auth-svc:9090/hook/dsg_setup_validation"
AUTH_KEY_ID_NOTIFICATION_URL: "http://auth-svc:9090/hook/key_id_notification"
ports:
- "8080:8080"
volumes:
- duo-server-data:/data
secrets:
- duo-signing-master-key
networks:
- duo-net
auth-svc:
container_name: auth-svc
image: ghcr.io/silence-laboratories/two-party-boilerplate-backend:c1555bf5af9592689f306f480651cbcafd076d16
ports:
- "9090:9090"
env_file:
- .env
environment:
SECRET_KEY: ${SECRET_KEY}
FEATURE_MOCK_AUTH_PROVIDER: ${FEATURE_MOCK_AUTH_PROVIDER:-"false"}
FEATURE_KEYID_LOOKUP_BY_TOKEN: "true"
FEATURE_ALLOW_ED25519: "true"
AUTH_PROVIDER: jwt
FACETEC_DEVICE_KEY: ${FACETEC_DEVICE_KEY}
FACETEC_API_URL: "https://api.facetec.com/api/v3.1/biometrics"
HELIUS_API_KEY: ${HELIUS_API_KEY}
AUTH0_DOMAIN: ${AUTH0_DOMAIN}
AUTH0_AUDIENCE: ${AUTH0_AUDIENCE}
depends_on:
- duo-server
networks:
- duo-net
volumes:
duo-server-data: null
secrets:
duo-signing-master-key:
file: ${MESSAGE_SIGNING_KEY:-./testdata/party_0_sk}

Before launch, generate the signing key file:

mkdir -p ./testdata
openssl rand 32 > ./testdata/party_0_sk

2. Update the .env with your credentials

Update the .env and fill in your credentials:

# From Auth0 setup
AUTH0_DOMAIN= # your-tenant.auth0.com
AUTH0_AUDIENCE= # your API identifier

# FaceTec device key — use the development key for local testing
FACETEC_DEVICE_KEY=

# Helius — optional, for transaction history when using boilerplate application
HELIUS_API_KEY= # from dev.helius.xyz

# Django secret key — unsafe default is fine for dev
SECRET_KEY=djangosecretkey

3. Run

docker compose -f docker-compose.hooks.with-duo-server.yml up

This starts auth-svc on port 9090 and duo-server on port 8080, connected on an internal bridge network.

You will see logs from both containers in the terminal:

duo-server  | WARN: The dotenv file is not set
duo-server | 2026-05-21T19:43:17.825909Z INFO sigpair_node: Creating SimpleStorage
duo-server | 2026-05-21T19:43:17.826633Z INFO sigpair_node: Party VK 01cfa1ff5424d14eb60614d7ddf65a32243d26ddf7000d10007853d7336395efe4
duo-server | 2026-05-21T19:43:17.826650Z INFO sigpair_node: Using HTTPTransport for auth hooks
duo-server | 2026-05-21T19:43:17.826983Z INFO auth_svc::config: DKGSetupValidatorHook: http://auth-svc:9090/hook/dkg_setup_validation
duo-server | 2026-05-21T19:43:17.827002Z INFO auth_svc::config: DSGSetupValidatorHook: http://auth-svc:9090/hook/dsg_setup_validation
duo-server | 2026-05-21T19:43:17.827010Z INFO auth_svc::config: KeyIdNotificationHook: http://auth-svc:9090/hook/key_id_notification
duo-server | 2026-05-21T19:43:17.827015Z INFO auth_svc::config: Initialized 3 auth hooks
duo-server | 2026-05-21T19:43:17.828547Z INFO sigpair_node: listening on 0.0.0.0:8080
auth-svc | Operations to perform:
auth-svc | Apply all migrations: admin, auth, contenttypes, sessions, src
auth-svc | Running migrations:
auth-svc | No migrations to apply.
auth-svc | 2026-05-21 19:43:20 [INFO] daphne.cli: Starting server at tcp:port=9090:interface=0.0.0.0
auth-svc | 2026-05-21 19:43:20 [INFO] daphne.server: HTTP/2 support not enabled (install the http2 and tls Twisted extras)
auth-svc | 2026-05-21 19:43:20 [INFO] daphne.server: Configuring endpoint tcp:port=9090:interface=0.0.0.0
auth-svc | 2026-05-21 19:43:20 [INFO] daphne.server: Listening on TCP address 0.0.0.0:9090

You will also find the Party VK <verifying-key> in the logs that you will use in your client side -- it's called CLOUD_NODE_VERIFYING_KEY by the phone client.


Notes for production

Django secret key

Replace the default djangosecretkey with a securely generated value:

echo "SECRET_KEY=$(openssl rand -base64 64 | tr -dc 'a-z0-9!@#$%^&*(-_=+')"

Duo-server exposure

Not all duo-server endpoints go through auth-svc hooks. Put duo-server behind a reverse proxy and only expose the endpoints that auth-svc authorizes. Block direct public access to the rest.

Next: Run the boilerplate application.