Custom domain setup with AWS Route53 and Cloudfront

This turned out to be easier than expected, but took some hunting. This solution assumes 2 things:

  • your custom Obsidian domain is a subdomain that you can define in Route53
  • your custom Obsidian domain does not include subdirectories (e.g. plamo.flyinggrizzly.net, not flyinggrizzly.net/plamo or hobbies.flyinggrizzly.net/plamo)

This approach uses the custom HTTP X-Header to indicate to Publish what site it’s serving.

Steps

  1. Choose your custom domain, like notes.example.com
  2. Create a Cloudfront distribution in AWS, with these settings:
    • Set the origin to publish.obsidian.md
    • Give it an alternate domain value that’s the same as your custom domain, so that it won’t error when we start routing to it from our DNS
    • Assign an SSL cert (this might be one you already have, if you have a wildcard cert for subdomains like *.example.com)
    • Set a custom header, with a name of X-Obsidian-Custom-Domain and a value of notes.example.com (/replace with your custom domain)
  3. In Route53, add a DNS CNAME entry for your subdomain, pointing at your Cloudfront distro’s URL (be sure to remove the https:// if you used the “Copy” button on the distribution page)
  4. Set your custom domain in the Obsidian Publish config settings

Give the DNS and CDN a minute to propagate, and you should now be able to access your published notes at your custom domain.

Other configurations

Obviously, the above is assuming you are using a subdomain without subdirectories.

I suspect this would work for a sub-folder, either by including that in the X-Header’s value, or firing a Lambda@Edge function on Viewer Request events.

The lambda could be used to rewrite your request URIs and get finer-grained control over the path patterns if there’s a mismatch between your filepaths in Obsidian and the request URLs being handled by Cloudfront. Something like this (not tested!):

// Running on Node 14.x runtime

exports.handler = (event, context, callback) => {
    const OBSIDIAN_CUSTOM_BASE_DOMAIN = 'example.com'
    
    const request = event.Records[0].cf.request
    
    // Identify the requested note resource path
    const path = request.uri

    // Update the request URI to hit Publish's serve endpoint
    request.uri = '/serve'
    
    request.querystring = `url=${OBSIDIAN_CUSTOM_BASE_DOMAIN}${path}`
    
    return callback(null, request)
};

2 Likes