Custom Domains for Published Vaults

Serve your published vault content on your own domain — DNS configuration, TXT verification, and TLS certificate activation.

intermediate15 min read

What You'll Build

Lifestream Vault lets you serve your published vault content on a domain you own — for example, docs.yourcompany.com — instead of the default *.lifestreamdynamics.com subdomain. The platform handles domain verification and TLS activation automatically.

By the end of this guide you will have:

  • Your custom domain added and verified via a DNS TXT record
  • A CNAME record pointing traffic to Lifestream Vault
  • TLS certificate activated (or configured in your reverse proxy for self-hosted deployments)
  • Your published vault content available at your custom domain
Plan Required

Custom domain support requires a Business tier subscription. Upgrade in Settings → Subscription. Published vaults on free and pro tiers are served from the default lifestreamdynamics.com domain.

Prerequisites

  • A Business tier subscription
  • A registered domain with DNS management access (e.g. Cloudflare, Route 53, Namecheap)
  • A published vault (go to vault → Settings → Publishing → Enable publishing)

Add Your Domain

The first step is to register your domain with Lifestream Vault. The API creates a domain record and returns a verification token — a unique string you must add to your DNS as a TXT record to prove ownership.

You can add a domain via the UI (Vault Settings → Custom Domains → Add Domain), the SDK, or the REST API.

typescript
import { LifestreamVaultClient } from '@lifestreamdynamics/vault-sdk';

const { client } = await LifestreamVaultClient.login(
  'https://vault.lifestreamdynamics.com',
  'you@example.com',
  'your-password',
);

const domain = await client.customDomains.create({
  domain: 'docs.yourcompany.com',
});

console.log('Domain ID:', domain.id);
console.log('Verification token:', domain.verificationToken);
// lsvault-verify=abc123...
// You will add this value to a DNS TXT record in the next step.

Configure DNS

Add two DNS records at your registrar or DNS provider. Log in to your DNS management console and create the following records:

RecordNameValue
TXT_lsv-verify.docs.yourcompany.comlsvault-verify=<token>
CNAMEdocs.yourcompany.comyour-vault-server.lifestreamdynamics.com

Replace <token> with the verificationToken value returned when you added the domain. Replace your-vault-server.lifestreamdynamics.com with the actual CNAME target shown in Vault Settings → Custom Domains.

Cloudflare users: add both records as DNS-only (grey cloud) initially. You can enable the orange cloud (proxy) after verification completes, but be aware that Cloudflare's proxy terminates TLS — see the TLS section below.

DNS propagation can take anywhere from a few minutes to 48 hours depending on your registrar and TTL settings. The domain-verification BullMQ worker checks automatically with exponential backoff — starting at 5-minute intervals and backing off up to 4 hours between checks. You do not need to manually trigger re-verification.

Domain Verification

After you add the DNS TXT record, the domain-verification BullMQ worker runs in the background and queries _lsv-verify.<yourdomain> via DNS. When it finds the correct TXT value, the domain status changes from pending to verified.

Poll the domain status to track progress:

typescript
const DOMAIN_ID = 'domain-uuid'; // from the create() response

// Poll until verified (in practice, set up a webhook or check the UI)
async function waitForVerification(maxAttempts = 10) {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const domain = await client.customDomains.get(DOMAIN_ID);

    console.log(`Attempt ${attempt + 1}: status = ${domain.status}`);

    if (domain.status === 'verified') {
      console.log('Domain verified! SSL status:', domain.sslStatus);
      return domain;
    }

    if (domain.status === 'failed') {
      throw new Error('Domain verification failed — check your DNS records.');
    }

    // Wait 60 seconds before next poll
    await new Promise((resolve) => setTimeout(resolve, 60_000));
  }

  throw new Error('Verification did not complete within the polling window.');
}

const verified = await waitForVerification();
console.log('Custom domain active:', verified.domain);

Verification typically completes within 15 minutes if your DNS records are correct and TTLs are low. If verification has not completed after approximately 48 hours (the maximum number of worker retry attempts), you will receive an email notification and the domain status will change to failed. Check your DNS records with dig TXT _lsv-verify.docs.yourcompany.com and re-add the domain if needed.

TLS Certificate

After domain verification succeeds, the domain sslStatus changes to active automatically on cloud-hosted deployments. Your custom domain is then fully operational over HTTPS.

Self-hosted deployments require additional reverse proxy configuration:

Caddy (recommended for automatic HTTPS):

docs.yourcompany.com {
  reverse_proxy localhost:4100
}

Caddy handles ACME certificate issuance and renewal automatically.

Nginx + Certbot:

server {
  listen 443 ssl;
  server_name docs.yourcompany.com;

  ssl_certificate     /etc/letsencrypt/live/docs.yourcompany.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/docs.yourcompany.com/privkey.pem;

  location / {
    proxy_pass http://localhost:4100;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

Run certbot --nginx -d docs.yourcompany.com to obtain and install the certificate.

Cloudflare proxy (orange cloud): If you are proxying through Cloudflare, TLS termination happens at Cloudflare's edge. Ensure the SSL/TLS mode in your Cloudflare dashboard is set to Full (strict)Flexible mode sends traffic to the origin over plain HTTP and can cause redirect loops.

Troubleshooting

ProblemSolution
Verification stuck in pendingCheck the TXT record with dig TXT _lsv-verify.docs.yourcompany.com +short — the value must exactly match the verificationToken
CNAME conflict errorRemove any existing A or AAAA records for the subdomain before adding the CNAME; a subdomain cannot have both a CNAME and an address record
SSL not activatingVerify the CNAME resolves to the correct target (dig CNAME docs.yourcompany.com); for self-hosted, check reverse proxy TLS configuration
Custom domain returns 404Verify the vault is published (PUT /api/v1/vaults/:vaultId/publish with { "published": true }) and the domain is linked to the correct vault
Mixed content warningsEnsure all assets referenced in your published content use HTTPS URLs; check for hardcoded http:// links in document frontmatter or embedded HTML
Cloudflare redirect loopSet Cloudflare SSL/TLS mode to Full (strict)Flexible mode causes an infinite HTTP↔HTTPS redirect loop with some reverse proxy configurations

What's Next