This has been originally posted as a Flotiq Deep Dive
How to add custom domains to free Heroku apps
Heroku is pretty great for hosting websites and their Deploy to Heroku
buttons are so awesome, especially with how they can be integrated with static website generators, like Gatsby. Heroku's free account is also quite capable, you are allowed to deploy up to 5 applications, hosted in their *.herokuapp.com
domain. But, as soon as you'd like to move this app to a custom domain - you have to pay. If you've already built and deployed your blog, for example using this tutorial your next step will probably be adding a custom domain for your blog.
Here's a quick tutorial how to get around this, with Cloudflare Workers.
Prerequisites:
- Cloudflare account (free)
- Cloudflare Workers enabled (free)
- Flotiq account (free)
Cloudflare Workers
Cloudflare is a global CDN (Contend Delivery Network), which provides websites across the globe with features like anti-DDoS protection, global content distribution and the possibility to run serverless applications "on the edge".
Cloudflare provides a pretty handy CLI tool to work with your Workers code, you can read more about how to get started here. In this tutorial, however, we will use the Cloudflare GUI to build the solution.
Creating the worker
Once you login to your Cloudflare account go to Menu / Workers. From the Workers dashboard select Create Worker.
You will be redirected to the Worker editor tool, which will be filled out with a Hello World code for you, this is the part that we'll update next.
Proxying content inside the Worker code
The Worker code below is going to take care of rewriting the URLs from yourdomain.com/blog/*
to your.herokuapp.com/*
.
// keep track of all our blog endpoints here
const myBlog = {
hostname: "flotiq-com-blog.herokuapp.com",
targetSubdirectory: "/blog",
assetsPathnames: ["/public/", "/assets/"]
}
async function handleRequest(request) {
// returns an empty string or a path if one exists
const formatPath = (url) => {
const pruned = url.pathname.split("/").filter(part => part)
return pruned && pruned.length > 1 ? `${pruned.join("/")}` : ""
}
const parsedUrl = new URL(request.url)
const requestMatches = match => new RegExp(match).test(parsedUrl.pathname)
// if its blog html, get it
if (requestMatches(myBlog.targetSubdirectory)) {
console.log("this is a request for a blog document", parsedUrl.pathname)
const targetPath = formatPath(parsedUrl).substr(myBlog.targetSubdirectory.length)
return fetch(`https://${myBlog.hostname}/${targetPath}`)
}
// if its blog assets, get them
if ([myBlog.assetsPathnames].some(requestMatches)) {
console.log("this is a request for blog assets", parsedUrl.pathname)
const assetUrl = request.url.replace(parsedUrl.hostname, myBlog.hostname);
return fetch(assetUrl)
}
console.log("this is a request to my root domain", parsedUrl.host, parsedUrl.pathname);
// if its not a request blog related stuff, do nothing
return fetch(request)
}
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
})
which is adapted from this Cloudflare article.
Simply paste this code in the Worker editor, replacing the original Hello World code. Don't forget to update your Heroku APP URL. Next - click Save and Deploy.
That's it! Cloudflare has deployed your worker to an automatically generated endpoint, you can start using it right away, the URL will be presented to you in the confirmation dialog.
Add routing
In order to publish your blog under a subfolder of your domain - in your domain dashboard click Workers
.
Next, click the Add Route
button.
And finally - define the route, where you'd like to display the Heroku-hosted content.
Conclusions
You can use a free Cloudflare Workers account to add custom domains to your free Heroku Apps account.
Top comments (3)
Hey Guys, let me know if this is useful, or if there's anything you'd like me to amend in the article. Also - the documentation page linked at the top contains more step-by-step screenshots from Cloudflare, so go over there if you'd like to verify.
I think this is helpful! But can you make more comprehensive step for these (e.g. explain what each block of code does?)? Because I have django app on heroku (which is free) that's not a blog and I can't find a way to understand your instructions because my app is not a blog. Thanks in advance!!
On a similar topic - you can also use Cloudflare to secure your API access.
Pretty important for JAMstack apps.