Skip to main content

Domains and Exposure

Wallets, verifiers, and relying parties reach Procivis One from outside your network. Core publishes URLs for them to call: credential offers, proof requests, DIDs, schemas, revocation lists, and published trust lists all point back to Core's base URL. If those URLs are not reachable from a phone or a remote service, issuance and verification fail.

For testing and development, any reachable URL works. For production, set your domain before you issue or publish anything you intend to keep. Changing Core's base URL later breaks the URLs embedded in what you have already issued or published.

Settings on this page are given as environment variables, except where a setting is in another file. For other ways to configure the services, see Configuration Mechanics.

Where to start​

Public and internal services​

ServiceHostnameReachable fromCalled by
Frontend and BFF, via oauth2_proxy<domain>InternetOperators' browsers
Keycloakkeycloak.<domain>InternetOperators' browsers, during sign-in
Corecore.<domain>InternetWallets and verifiers
Bridgebridge.<domain>InternetOIDC relying parties
WRPRwrpr.<domain>InternetWallets, Access and Registration Certificate issuers
Databases, Redis—Internal onlyProcivis One services

Core serves both public protocol endpoints (/ssi, /.well-known) and management endpoints (/api) on the same hostname. To keep management endpoints off the public internet, see API Endpoint Zones. Core's /health and /metrics endpoints are for internal use and should not be routed publicly.

To serve different domains, for example one per ecosystem or customer, run separate Core instances, each with its own base URL.

URL settings​

Each section below covers one URL and lists the settings that must match it. The Quick start location column shows where each setting lives in the Full Stack Quick Start bundle. If you have reorganized your configuration, the setting names stay the same.

Set the base URLs listed here. The services derive other URLs from them, such as the BFF's login URL from frontend.url. You only need to set a derived URL if it must differ from the derived value. See Java services.

Core public URL​

The URL wallets and verifiers use to reach Core. On a domain: https://core.<domain>.

ServiceSettingQuick start location
CoreONE_app__coreBaseUrlenv/.core.env

Desk URL​

The URL operators use to reach the Desk. On a domain: https://<domain>.

ServiceSettingQuick start location
BFFfrontend.urlenv/.bff.env
BFFsts.token.issenv/.bff.env
oauth2_proxyredirect_url (<Desk URL>/oauth2/callback)conf/oauth2_proxy/oauth2-proxy.cfg
Keycloaklogin-client redirect URIs, web origins, post-logout redirect URIsmaster-realm.json

The BFF uses sts.token.iss as the issuer of the tokens it signs, and validates incoming tokens against the same value. Other services that validate BFF tokens must use the same issuer.

Identity provider URLs​

The URLs services use to sign users in and obtain or validate tokens. For the starter Keycloak on a domain, these start with https://keycloak.<domain>/realms/master. When you connect your own identity provider, use its URLs instead.

ServiceSettingQuick start location
BFFsts.iam.tokenValidation.issenv/.bff.env
BFFsts.iam.tokenValidation.jwksUrienv/.bff.env
BFFauth.technicalUserCredentials.iamTokenEndpointUrlenv/.bff.env
BFFfrontend.iamLinkenv/.bff.env
Bridgespring.security.oauth2.client.provider.keycloak.token-urienv/.bridge.env
WRPRspring.security.oauth2.client.provider.keycloak.token-urienv/.wrpr.env
oauth2_proxyissuerURLconf/oauth2_proxy/alpha-config.yml
oauth2_proxybackendLogoutURLconf/oauth2_proxy/alpha-config.yml
Keycloak (starter only)KEYCLOAK_HOSTNAMEenv/.keycloak.env

Always set frontend.iamLink. Its default does not point to your identity provider.

Service-to-service URLs​

The URLs the BFF, Bridge, and WRPR use to reach other Procivis One services.

ServiceSettingQuick start location
BFFcore.api.url, bridge.api.url, wrpr.api.urlenv/.bff.env
Bridgecore.api.urlenv/.bridge.env
WRPRcore.api.urlenv/.wrpr.env

These can point to either the public hostname, such as https://core.<domain>, or the internal service name, such as http://core:3000. The localhost bundle uses internal names; the domain bundle uses public hostnames.

Routing and certificates​

The hostnames your reverse proxy routes and the domains oauth2_proxy accepts.

ServiceSettingQuick start location
TraefikHost() rules for each public servicedocker-compose.yml
Traefikacme.email (Let's Encrypt account)docker-compose.yml
oauth2_proxywhitelist_domainsconf/oauth2_proxy/oauth2-proxy.cfg

Feature-specific URLs​

Some features have their own URL settings. They are not set in the quick start bundle and only need a value if you use the feature.

ServiceSettingFeature
BFF, BridgeappLink.urlMobile app links
CoreONE_verifierProvider__<instance>__params__public__accessCertificateConfiguration__providerUrlVerifier providing
CoreONE_walletProvider__<instance>__params__public__walletLinkWallet providing
CoreONE_walletProvider__<instance>__params__public__userAuthentication__redirectUriWallet providing
CoreONE_did__WEBVH__params__public__externalHostingUrldid:webvh hosted elsewhere

Replace <instance> with the name of the instance in your configuration.

Local testing with a tunnel​

On localhost, Core's base URL is http://localhost:3000, which a mobile wallet cannot reach. To test wallet flows without a domain, expose Core through a tunnel such as ngrok or Cloudflare Tunnel.

warning

A tunnel makes all of Core reachable from the internet, including the /api management endpoints. These are protected only by the starter static token, which every installation shares. Replace the starter tokens before you start a tunnel. See Secrets and Keys.

  1. Set the tunnel URL as Core's base URL in env/.core.env. Use a stable hostname: if the tunnel URL changes on restart, anything issued under the previous URL stops working. A free ngrok account includes one static domain, shown in the ngrok dashboard.

    ONE_app__coreBaseUrl="https://<your-static-domain>"
  2. Apply the change:

    docker compose up -d

    Compose recreates the services whose configuration changed.

  3. Start a tunnel to Core on port 3000, and leave it running while you test. For example, with ngrok:

    ngrok http 3000 --url https://<your-static-domain>
  4. Create a new credential offer or proof request. Its URL should contain your tunnel domain. Offers and requests created before the change still point to localhost.

Only Core needs a tunnel for issuance and verification. Operator sign-in and the Desk continue to work on http://localhost.

To see the requests that reach Core through an ngrok tunnel, open the ngrok inspector at http://localhost:4040.

Moving from localhost to a domain​

The simplest path is a fresh domain deployment, following Option B in the Full Stack Quick Start. Anything issued or published under localhost URLs is not valid on the new domain, so there is little to carry over.

If you changed any starter secrets or keys in your localhost deployment, copy those changes into the domain bundle before starting.

Keeping existing Keycloak data​

The starter realm is imported only on first start. If you reuse an existing Keycloak database instead of starting fresh, the realm keeps its localhost URLs. Update them in the Keycloak admin console:

  1. Sign in at https://keycloak.<domain>/admin with the bootstrap admin credentials (default: admin / admin).

  2. Open the login-client client and set:

    SettingValue
    Valid redirect URIshttps://<domain>/oauth2/callback
    Valid post logout redirect URIshttps://<domain>
    Web originshttps://<domain>
  3. Change the admin password. The default is shared by every installation.

Existing reverse proxy or load balancer​

The domain bundle includes Traefik, which terminates TLS and requests certificates from Let's Encrypt. If your server already runs a reverse proxy, or sits behind a load balancer that terminates TLS, use that instead:

  1. Remove the traefik service and the traefik.* labels from docker-compose.yml.

  2. Publish the public services' ports to the host. Bind them to 127.0.0.1 if your proxy runs on the same server:

    oauth2_proxy:
    ports:
    - "127.0.0.1:4180:4180"
    core:
    ports:
    - "127.0.0.1:3000:3000"
    keycloak:
    ports:
    - "127.0.0.1:8080:8080"
    bridge:
    ports:
    - "127.0.0.1:9000:9000"
    wrpr:
    ports:
    - "127.0.0.1:9001:9001"
  3. Route each hostname to its port:

    HostnameUpstream
    <domain>oauth2_proxy, port 4180
    core.<domain>core, port 3000
    keycloak.<domain>keycloak, port 8080
    bridge.<domain>bridge, port 9000
    wrpr.<domain>wrpr, port 9001

    If you change a service's listening port, such as Core's ONE_app__serverPort, update its upstream to match.

  4. Forward the X-Forwarded-Proto, X-Forwarded-Host, and X-Forwarded-For headers. Services use them to generate correct https URLs behind the proxy.

  5. Do not route monitoring endpoints publicly: Core's /health and /metrics, and the /actuator paths of the BFF, Bridge, and WRPR.

Remove the Traefik settings from Routing and certificates; all other URL settings stay the same.