Run Your Own Backend (Advanced)
Only needed if you're self-hosting. The Quick Start already runs against our deployed Duo sandbox — skip this page unless you want to point the app at your own duo-server + auth-svc.
The boilerplate communicates with two backend services that work together:
duo-server— the MPC cloud node. It holds the cloud-side keyshare and participates in every keygen and signing operation.auth-svc— the auth middleware. It handles user and device registration, and authorizes every operationduo-serverperforms by responding to hook calls.
Think of it this way: duo-server is the vault. auth-svc is the doorman. The vault calls the doorman before opening for any keygen or sign request.
For full auth-svc setup instructions (Docker Compose, environment variables, and hook configuration), see the auth-svc documentation.
Self-hosting checklist
Follow this order when replacing the sandbox with your own backend:
- Run the Quick Start against the deployed sandbox first. This verifies your local React Native, Expo, iOS, and Android setup before you introduce custom backend configuration.
- Set up third-party services. Auth0 and FaceTec values must be shared by the app and
auth-svc; Google and WalletConnect values are app-only. - Configure
auth-svc, including the Auth0 API/audience, FaceTec values, database, and hook configuration. - Run
auth-svcwithduo-server, then copy theduo-serverURL and the cloud verifying key printed in theduo-serverlogs. - Replace the
EXPO_PUBLIC_DUO_*, Auth0, FaceTec, Google, and WalletConnect values in the app's.env. - Restart the app so Expo reloads
.env. The app defaults to the Duo Demo server preset; after you replaceEXPO_PUBLIC_DUO_*, that default preset points at your backend. Use Server settings -> Custom Backend only when you want to enter backend values at runtime without changing.env.
Point the app at your backend
Once your backend is running, set the Duo preset values in the app's .env (these override the sandbox defaults from .env.example):
| Variable | Where to find it |
|---|---|
EXPO_PUBLIC_DUO_CLOUD_NODE_URL | The URL of duo-server (e.g. https://your-node.example.com) |
EXPO_PUBLIC_DUO_CLOUD_NODE_VERIFYING_KEY | The hex verifying key printed in duo-server logs on startup |
EXPO_PUBLIC_DUO_BACKEND_BASE_URL | The HTTP base URL of auth-svc (e.g. https://your-auth-svc.example.com) |
These seed the Duo Demo entry in the in-app Server settings, and the app selects Duo Demo by default. After replacing these values and restarting the app, the default Duo path uses your backend. You can also enter a backend at runtime via Server settings → Custom Backend without rebuilding.
Your app config must match your auth-svc config. auth-svc validates the JWT and the FaceTec session, so the values baked into the app have to match what auth-svc is configured with — otherwise login and backup/recovery will fail:
App .env | Must match auth-svc's |
|---|---|
EXPO_PUBLIC_AUTH0_DOMAIN, EXPO_PUBLIC_AUTH0_CLIENT_ID, EXPO_PUBLIC_AUTH0_AUDIENCE | Auth0 tenant / API audience |
EXPO_PUBLIC_FACETEC_DEVICE_KEY_IDENTIFIER, EXPO_PUBLIC_ENCRYPTION_KEY | FaceTec device key + encryption key |
See Third-Party Services to create these and keep both sides in sync.
Running locally? Use these addresses depending on your target:
| Target | Backend URL |
|---|---|
| iOS Simulator | http://localhost:9090 |
| Android Emulator | http://10.0.2.2:9090 |
| Physical device | Your machine's LAN IP (e.g. http://192.168.1.x:9090) or use ngrok |
The same rule applies to the duo-server WebSocket URL — replace localhost with 10.0.2.2 or your LAN IP accordingly.