External DID Web Hosting

By default, did:web documents are served from your Enterprise Stack domain (e.g. waltid.enterprise.cloud). Production deployments usually want a branded domain instead — for example, did:web:dids.example.com:alice resolving at https://dids.example.com/alice/did.json.

This guide covers the full setup: registry configuration, host alias, DNS, reverse proxy, DID creation, and verification.

New to DID Registry concepts? Start with the Overview to understand how did:web identifiers map to HTTPS URLs and how the registry fits into the service stack.

What you'll configure

ComponentPurpose
Organization-level DID RegistryRoot registry for org-scoped resolution
Tenant didRegistry configLinks the tenant to its registry service
Host aliasMaps your custom domain to the tenant
DNS + reverse proxyRoutes HTTPS traffic from your domain to the Enterprise Stack
DID creationUses your custom domain in the domain parameter

Prerequisites

  • A walt.id Enterprise Stack organization with admin access
  • A tenant with a DID Registry service and DID Store (see Setup)
  • A custom domain you control (e.g. dids.waltid.org)
  • Access to DNS and a reverse proxy (Nginx, Traefik, or Kubernetes Ingress)

Step 1: Configure Organization-Level Root DID Registry

Before configuring the tenant-level DID registry, you need to set up an organization-level root DID registry:

  1. Create Organization-Level DID Registry Service:
CURL

Endpoint: /v1/{target}/resource-api/services/create | API Reference

Example Request

curl -X 'POST' \
  'https://{orgID}.enterprise.cloud/v1/{target}/resource-api/services/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "did-registry"
}'

Path Parameters

  • orgID: - When performing operations within an organization, it is essential to use the organization's Base URL or another valid host alias. For example, if your organization is named waltid, your default Base URL will be waltid.enterprise.cloud.
  • target: resourceIdentifier - The target indicates the organization in which to create the new organization level DID Registry service — a 2-segment path directly under the org, with no tenant, e.g. waltid.did-registry-main

Header Parameters

  • Authorization: - Bearer token for Enterprise Stack authentication. Format: Bearer {yourToken}.

Body Parameters

  • type: serviceType - Specifies the type of service to create. In our case did-registry
  1. Set Up Root DID Registry:
CURL

Endpoint: /v1/organization/update-config | API Reference

Example Request

curl -X 'POST' \
  'https://{orgID}.enterprise.cloud/v1/organization/update-config' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "rootDidRegistry": "waltid.did-registry-main"
}'

Path Parameters

  • orgID: - When performing operations within an organization, it is essential to use the organization's Base URL or another valid host alias. For example, if your organization is named waltid, your default Base URL will be waltid.enterprise.cloud.

Header Parameters

  • Authorization: - Bearer token for Enterprise Stack authentication. Format: Bearer {yourToken}.

Body Parameters

  • rootDidRegistry: resourceIdentifier - The ID of the DID Registry Service to be used for organization-level DIDs, e.g. waltid.did-registry-main

Step 2: Configure Tenant-Level DID Registry

First, ensure that your tenant has the DID registry service properly configured:

This setting is stored and returned by the tenant config endpoints. The resolution path this guide uses (organization-root, Step 6) is driven entirely by rootDidRegistry (Step 1) and does not read this value — didRegistry matters for tenant-scoped resolution paths instead, see Tenant-level DIDs.

CURL

Endpoint:/v1/{target}/tenant-api/tenants/config/update | API Reference

Example Request

curl -X 'POST' \
  'https://{orgID}.enterprise.cloud/v1/{target}/tenant-api/tenants/config/update' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "didRegistry": "waltid.tenant.did-registry-main"
}'

Body

{
  "didRegistry": "waltid.tenant.did-registry-main"
}

Path Parameters

  • orgID: - When performing operations within an organization, it is essential to use the organization's Base URL or another valid host alias. For example, if your organization is named waltid, your default Base URL will be waltid.enterprise.cloud.
  • target: resourceIdentifier - The target indicates the tenant for which to update the configuration ({organizationID}.{tenantID}), e.g. waltid.tenant

Header Parameters

  • Authorization: - Bearer token for Enterprise Stack authentication. Format: Bearer {yourToken}.

Body Parameters

  • didRegistry: String - The ID of the DID Registry service to be associated with the tenant. This should be the fully qualified ID of your DID registry service.

Step 3: Create Host Alias for Tenant

Create a host alias for your tenant that points to your custom domain:

CURL

Endpoint:/v1/{target}/host-alias-api/host-aliases/create | API Reference

Example Request

curl -X 'POST' \
  'https://{orgID}.enterprise.cloud/v1/{target}/host-alias-api/host-aliases/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "domain": "dids.waltid.org"
}'

Body

{
  "domain": "dids.waltid.org"
}

Path Parameters

  • orgID: - When performing operations within an organization, it is essential to use the organization's Base URL or another valid host alias. For example, if your organization is named waltid, your default Base URL will be waltid.enterprise.cloud.
  • target: resourceIdentifier - The target indicates the tenant for which to create the host alias ({organizationID}.{tenantID}.{host_alias_id}), e.g. waltid.tenant.my-alias

Header Parameters

  • Authorization: - Bearer token for Enterprise Stack authentication. Format: Bearer {yourToken}.

Body Parameters

  • domain: String - The custom domain that you want to use for your tenant. This is the domain where your DIDs will be available.

Step 4: Configure DNS and Reverse Proxy (Customer Side)

On the customer side, you need to configure your DNS and set up a reverse proxy to point your custom domain to the enterprise stack server:

  1. DNS Configuration:
    • Create a DNS record for your custom domain (e.g., dids.waltid.org) pointing to your reverse proxy server.
  2. Reverse Proxy Setup:
    • Set up a reverse proxy (e.g., Nginx, Apache, Traefik) on your server.
    • Configure SSL/TLS for your custom domain.
    • Configure the reverse proxy to forward requests from your custom domain to the enterprise stack server.

Example Nginx Configuration:

server {
    listen 443 ssl;
    server_name dids.waltid.org;

    ssl_certificate /path/to/your/certificate.crt;
    ssl_certificate_key /path/to/your/private.key;

    location / {
        proxy_pass https://waltid.enterprise.cloud;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Example Kubernetes Ingress Configuration:

If you're using Kubernetes, you can set up an Ingress resource to route traffic to your enterprise API service:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: dids-waltid-org-enterprise-ingress
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  ingressClassName: "nginx"
  tls:
    - hosts:
        - dids.waltid.org
      secretName: did-waltid-org-tls
  rules:
    - host: dids.waltid.org
      http:
        paths:
          - path: /auth/
            pathType: Prefix
            backend:
              service:
                name: waltid-enterprise-api
                port:
                  name: http
          - path: /v1/
            pathType: Prefix
            backend:
              service:
                name: waltid-enterprise-api
                port:
                  name: http
          - path: /.well-known/vct/v1/
            pathType: ImplementationSpecific
            backend:
              service:
                name: waltid-enterprise-api
                port:
                  name: http
          - path: /swagger
            pathType: Prefix
            backend:
              service:
                name: waltid-enterprise-api
                port:
                  name: http
          - path: /api.json
            pathType: ImplementationSpecific
            backend:
              service:
                name: waltid-enterprise-api
                port:
                  name: http
          - path: /.*/did\.json$
            pathType: ImplementationSpecific
            backend:
              service:
                name: waltid-enterprise-api
                port:
                  name: http
          - path: /livez
            pathType: Prefix
            backend:
              service:
                name: waltid-enterprise-api
                port:
                  name: http
          - path: /features/
            pathType: Prefix
            backend:
              service:
                name: waltid-enterprise-api
                port:
                  name: http
          - path: /debug/
            pathType: Prefix
            backend:
              service:
                name: waltid-enterprise-api
                port:
                  name: http

This Ingress configuration:

  • Sets up TLS for the dids.waltid.org domain using cert-manager
  • Routes various API paths to the waltid-enterprise-api service
  • Includes a regex path for DID documents (/.*/did.json$)

Step 5: Create DID in DID Store

Create a DID in the DID Store, making sure to use your custom domain in the domain parameter:

CURL

Endpoint: /v1/{target}/did-service-api/dids/create/web | API Reference

Example Request

curl -X 'POST' \
  'https://{orgID}.enterprise.cloud/v1/{target}/did-service-api/dids/create/web' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer {yourToken}' \
  -d '{
  "type": "single_key_reference",
  "keyReference": "waltid.tenant.kms1.secp256r1",
  "domain": "dids.waltid.org",
  "path" : "user1"
}'

Body

{
  "type": "single_key_reference",
  "keyReference": "waltid.tenant.kms1.secp256r1",
  "domain": "dids.waltid.org",
  "path" : "user1"
}

Path Parameters

  • orgID: - When performing operations within an organization, it is essential to use the organization's Base URL or another valid host alias. For example, if your organization is named waltid, your default Base URL will be waltid.enterprise.cloud.
  • target: resourceIdentifier - The DID Service instance to create the DID in ({organizationID}.{tenantID}.{didServiceID}), e.g. waltid.tenant.did1

Header Parameters

  • Authorization: - Bearer token for Enterprise Stack authentication. Format: Bearer {yourToken}.

Body Parameters

  • keyReference: resourceIdentifier - Specifies the key for which to generate a DID + DID Document. Please make sure that the key is stored in a KMS service under the same tenant as the DID service.
  • domain: string - The domain name to be used for the DID:web. This should be your custom domain (e.g., dids.waltid.org).
  • path: string - The path to be used for the DID:web (e.g., user1).

Response

  • 201 - DID created successfully.
{
  "did": "did:web:dids.waltid.org:user1",
  "document": {
    "@context": [
      "https://www.w3.org/ns/did/v1",
      "https://w3id.org/security/suites/jws-2020/v1"
    ],
    "id": "did:web:dids.waltid.org:user1",
    "verificationMethod": [
      {
        "id": "did:web:dids.waltid.org:user1#key1",
        "type": "JsonWebKey2020",
        "controller": "did:web:dids.waltid.org:user1",
        "publicKeyJwk": {
          "kty": "EC",
          "crv": "P-256",
          "kid": "key1",
          "x": "...",
          "y": "..."
        }
      }
    ],
    "assertionMethod": [
      "did:web:dids.waltid.org:user1#key1"
    ],
    "authentication": [
      "did:web:dids.waltid.org:user1#key1"
    ],
    "capabilityDelegation": [
      "did:web:dids.waltid.org:user1#key1"
    ],
    "capabilityInvocation": [
      "did:web:dids.waltid.org:user1#key1"
    ],
    "keyAgreement": [
      "did:web:dids.waltid.org:user1#key1"
    ]
  }
}

Step 6: Verify DID Resolution

Once you've completed the above steps, your DID should be available to resolve at your custom domain:

did:web:dids.waltid.org:user1

You can verify this by accessing the DID document directly at:

https://dids.waltid.org/user1/did.json

Troubleshooting

If you're having issues with external DID web hosting, check the following:

  1. Organization-Level DID Registry: Ensure that your organization has the correct root DID registry configured.
  2. Tenant Configuration: Ensure that your tenant has the correct DID registry configured.
  3. Host Alias: Verify that the host alias has been created correctly with your custom domain.
  4. DNS Configuration: Check that your DNS records are pointing to the correct server.
  5. Reverse Proxy: Ensure that your reverse proxy is correctly configured to forward requests to the enterprise stack server.
  6. DID Creation: Make sure you used your custom domain when creating the DID.
Last updated on August 18, 2026