Hosting DIDs on Your Domain
By default, Layr8 hosts your DID on our infrastructure at <node-id>.node.layr8.io. However, for organizations that want greater control and sovereignty over their identity, you can host your DID on your own domain using the Layr8 DID Webserver. This guide walks through the setup process.
Why Host Your Own DID?
Hosting your DID on your domain provides several benefits:
- Brand consistency - Your DID matches your domain (e.g.,
did:web:acme.com) - Full control - You manage the domain and DID routing
- Trust - Partners recognize and trust your domain
- Portability - Change DID providers without changing your identifier
How It Works
The Layr8 DID Webserver acts as a proxy that:
- Receives DID resolution requests at your domain
- Fetches the DID document from your Layr8 node
- Serves the document from your domain with proper caching
- Maintains high availability with multiple origin nodes
did:web:example.com → https://example.com/.well-known/did.json ↓ DID Webserver ↓ Fetches from Layr8 Node ↓ Returns DID DocumentPrerequisites
Before you begin, ensure you have:
- Domain ownership - Administrative access to your domain’s DNS
- Server infrastructure - A server to run the DID Webserver
- Layr8 Node - Active node with your DID document(s)
Installation Options
Option 1: Docker Deployment
The easiest way to deploy is using Docker:
# Pull the DID Webserver imagedocker pull ghcr.io/layr-8/did-webserver:latest
# Create node configurationecho "your-node-id.node.layr8.io" > node_list.txt
# Run the containerdocker run -d \ --name did-webserver \ -p 4000:4000 \ -e PORT=4000 \ -e CACHE_TTL=3600 \ -e FILE_PATH=/app/config/node_list.txt \ -v $(pwd)/node_list.txt:/app/config/node_list.txt \ ghcr.io/layr-8/did-webserver:latestOption 2: Direct Installation
For more control, install directly on your server:
# Prerequisites: Elixir 1.14+ and Erlang/OTP 25+
# Clone the repositorygit clone https://github.com/layr-8/did-webserver.gitcd did-webserver
# Install dependenciesmix deps.get
# Configure your nodeecho "your-node-id.node.layr8.io" > priv/static/node_list.txt
# Run in productionMIX_ENV=prod mix run --no-haltOption 3: Kubernetes Deployment
For production deployments, use Kubernetes:
apiVersion: apps/v1kind: Deploymentmetadata: name: did-webserverspec: replicas: 3 selector: matchLabels: app: did-webserver template: metadata: labels: app: did-webserver spec: containers: - name: did-webserver image: ghcr.io/layr-8/did-webserver:latest ports: - containerPort: 4000 env: - name: PORT value: "4000" - name: CACHE_TTL value: "3600" volumeMounts: - name: node-config mountPath: /app/config volumes: - name: node-config configMap: name: did-webserver-nodes---apiVersion: v1kind: ConfigMapmetadata: name: did-webserver-nodesdata: node_list.txt: | your-node-id.node.layr8.io backup-node.node.layr8.ioConfiguration
Environment Variables
Configure the DID Webserver with these environment variables:
| Variable | Description | Default |
|---|---|---|
PORT | HTTP server port | 4000 |
FILE_PATH | Path to node list file | priv/static/node_list.txt |
CACHE_TTL | Cache time-to-live (seconds) | 3600 (1 hour) |
DEPLOYMENT_ENV | Environment (dev/staging/prod) | dev |
Node List Configuration
The node_list.txt file specifies origin nodes to fetch DID documents from:
# Primary nodemercury.node.layr8.io
# Backup nodes (optional)venus.node.layr8.ioearth.node.layr8.ioFeatures:
- One node per line
- Comments supported with
# - Monitored for changes (updates every 5 seconds)
- Multiple nodes provide redundancy
Web Server Configuration
Configure your web server (Nginx/Apache) to proxy to the DID Webserver:
Nginx Configuration:
server { listen 443 ssl http2; server_name example.com;
# SSL configuration ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem;
# DID document endpoint location /.well-known/did.json { proxy_pass http://localhost:4000; 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;
# Caching headers add_header Cache-Control "public, max-age=3600"; add_header Content-Type "application/json";
# CORS headers add_header Access-Control-Allow-Origin "*"; add_header Access-Control-Allow-Methods "GET, OPTIONS"; }
# Health check endpoint location /health { proxy_pass http://localhost:4000; }
# Path-based DIDs (optional) location ~ ^/(.+)/did\.json$ { proxy_pass http://localhost:4000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }}Apache Configuration:
<VirtualHost *:443> ServerName example.com
SSLEngine on SSLCertificateFile /path/to/cert.pem SSLCertificateKeyFile /path/to/key.pem
# Enable proxy modules ProxyRequests Off ProxyPreserveHost On
# DID document endpoint <Location "/.well-known/did.json"> ProxyPass http://localhost:4000/.well-known/did.json ProxyPassReverse http://localhost:4000/.well-known/did.json
Header set Access-Control-Allow-Origin "*" Header set Access-Control-Allow-Methods "GET, OPTIONS" Header set Cache-Control "public, max-age=3600" </Location>
# Health check <Location "/health"> ProxyPass http://localhost:4000/health ProxyPassReverse http://localhost:4000/health </Location></VirtualHost>URL Patterns Supported
The DID Webserver supports two URL patterns:
1. Domain-level DIDs
DID: did:web:example.comURL: https://example.com/.well-known/did.json2. Path-based DIDs
DID: did:web:example.com:users:aliceURL: https://example.com/users/alice/did.json
DID: did:web:example.com:departments:financeURL: https://example.com/departments/finance/did.jsonHigh Availability Setup
For production environments, implement high availability:
1. Multiple DID Webserver Instances
Run multiple instances behind a load balancer:
upstream did_webservers { server did-webserver-1:4000 max_fails=3 fail_timeout=30s; server did-webserver-2:4000 max_fails=3 fail_timeout=30s; server did-webserver-3:4000 max_fails=3 fail_timeout=30s;}
location /.well-known/did.json { proxy_pass http://did_webservers; proxy_next_upstream error timeout http_500 http_502 http_503;}2. Multiple Origin Nodes
Configure multiple Layr8 nodes for redundancy:
primary.node.layr8.iosecondary.node.layr8.iotertiary.node.layr8.ioThe webserver tries nodes concurrently and uses the first successful response.
3. CDN Integration
Use a CDN for global distribution:
// CloudFlare Page Rule Example{ "url": "example.com/.well-known/did.json", "actions": { "cache_level": "cache_everything", "edge_cache_ttl": 3600, "browser_cache_ttl": 3600 }}Monitoring and Operations
Health Checks
Monitor your DID Webserver health:
# Basic health checkcurl https://example.com/health
# DID resolution checkcurl https://example.com/.well-known/did.json
# Automated monitoring script#!/bin/bashwhile true; do if ! curl -sf https://example.com/.well-known/did.json > /dev/null; then echo "DID resolution failed at $(date)" # Send alert fi sleep 60doneMetrics and Logging
The DID Webserver provides detailed logging:
# Log examples:[info] GET /.well-known/did.json[info] Fetching DID document from origin nodes[info] Cache hit for did:web:example.com[info] Successfully fetched from mercury.node.layr8.io in 45ms[error] All origin nodes failed for did:web:example.comEnable debug logging for troubleshooting:
DEPLOYMENT_ENV=dev PORT=4000 ./did-webserverCache Management
The webserver includes intelligent caching:
- Default TTL: 1 hour (configurable)
- Cache key: Based on DID identifier
- Automatic invalidation: On origin node changes
- Memory-based: Fast retrieval
Adjust cache TTL based on your needs:
# Shorter TTL for frequently changing DIDsCACHE_TTL=300 ./did-webserver # 5 minutes
# Longer TTL for stable DIDsCACHE_TTL=86400 ./did-webserver # 24 hoursMigration Guide
Step 1: Preparation
- Set up DID Webserver on your infrastructure
- Configure it to fetch from your Layr8 node
- Test thoroughly with direct IP access
- Verify DID document is correct
Step 2: DNS Configuration
Add DNS records pointing to your DID Webserver:
; A record for IPv4example.com. A 203.0.113.10
; AAAA record for IPv6example.com. AAAA 2001:db8::10
; Or CNAME if using a load balancerexample.com. CNAME lb.example.com.Step 3: SSL/TLS Setup
Ensure HTTPS is properly configured:
# Using Let's Encryptcertbot certonly --webroot -w /var/www/html -d example.com
# Test SSL configurationopenssl s_client -connect example.com:443 -servername example.comStep 4: Update Partner Connections
- Notify partners of your new DID
- Update documentation and integrations
- Maintain old DID during transition period
- Monitor both DIDs for activity
Step 5: Verification
# Resolve your new DIDcurl https://example.com/.well-known/did.json
# Test with Layr8 toolslayr8 did resolve did:web:example.com
# Verify messaging workslayr8 message send --to did:web:example.com --type testTroubleshooting
Common Issues and Solutions
DID Resolution Returns 404
- Check node_list.txt contains valid nodes
- Verify origin node has your DID document
- Check webserver logs for fetch errors
SSL Certificate Errors
- Ensure certificate covers your domain
- Check certificate chain is complete
- Verify port 443 is accessible
Slow Response Times
- Check network connectivity to origin nodes
- Increase cache TTL if appropriate
- Add more origin nodes for redundancy
“All origin nodes failed” Error
- Verify node names in node_list.txt
- Check network connectivity
- Ensure origin nodes are operational
Debug Mode
Enable detailed debugging:
# Run with debug loggingDEPLOYMENT_ENV=dev ./did-webserver
# Check specific resolutioncurl -v https://example.com/.well-known/did.json
# Monitor cache behaviorcurl -H "Cache-Control: no-cache" https://example.com/.well-known/did.jsonSecurity Best Practices
- Use HTTPS Only - did:web requires HTTPS
- Implement Rate Limiting - Prevent DoS attacks
- Monitor Access Logs - Detect unusual patterns
- Keep Software Updated - Regular security patches
- Restrict Management Access - Secure node_list.txt updates
Advanced Configurations
Multi-Domain Hosting
Host multiple domains on one webserver:
server { server_name example.com example.org example.net;
location /.well-known/did.json { proxy_pass http://localhost:4000; proxy_set_header Host $host; }}Geographic Distribution
Deploy regionally for better performance:
# US Regionus-east-1: nodes: - us-east.node.layr8.io - us-central.node.layr8.io
# EU Regioneu-west-1: nodes: - eu-west.node.layr8.io - eu-central.node.layr8.io
# APAC Regionap-southeast-1: nodes: - ap-south.node.layr8.io - ap-northeast.node.layr8.ioFurther Reading
- DID Webserver Source Code
- did:web Method Specification
- DID Core Specification
- Decentralized Identifiers