Building a Custom Landing Page

Wherein I save the world from another NXDOMAIN or WIP page.

Building a Custom Landing Page

I am a big proponent of portability in IT. In that regard, personal custom email domains are great; they let you easily change the backend email provider you use while maintaining a single identity to the rest of the world. You’re not tied to Gmail/Yahoo/Hotmail but something uniquely you.

But what happens when someone tries to browse a website associated with your email? Having something to show them is excellent, and it’s not that hard. To get started on building a quick landing page, I set out a couple of objectives to hit:

  • It should be fast, free, and flexible.
  • It should show some flair.
  • It should be uniquely me.
  • It needs to involve my friends.

So what I came to can be found publically on my GitHub; it looks a little like this, and what follows is an explanation of how I achieved these objectives and had fun along the way.

Screenshot of the finished page

Fast, Free, and Flexible

I compared several static website hosting services but, in the end, settled on Cloudflare Pages because of how easily it integrated into my DNS infrastructure, also based on Cloudflare.

Building the Site

The site itself is static, but I wanted the ability to extend it easily while travelling without worrying about modifying large parts of the codebase. The pages build process tracks the GitHub repository and automatically builds from the main branch. It runs a script within the build command ’node build/build.js’ that executes a set of defined build modules. So far, the following two build modules have been defined:

  • fetchfonts.js: Parses’ data/greetings.json’ containing different messages and their associated fonts. It then fetches the required font styles from Google Fonts, optimises them by including only the unique characters used in the messages, and combines them into a single file called ‘webfonts.css’.
  • parsebg.js: Parses the ‘bg’ directory for background images stored with the ‘background-position’ CSS property in their filename. It then builds a ‘data/backgrounds.json’ file. For ‘js/background.js’ to work entirely as client-side javascript, it needs this index; this approach makes it trivial to add new backgrounds, as all information is contained in the filename.

Routing the Page

For various reasons, I’ve accumulated several domains over time, and I wanted to be able to serve this landing page across a number of them efficiently without leaving the Cloudflare platform and having to establish a server to perform the redirection for me.

To maximise functionality and minimise costs, I went with a combination of defining Custom Domains in Cloudflare Pages and Workers.

Cloudflare Pages custom domains configuration.

I created a new Worker to intercept requests coming into Cloudflare to hit any of these domains. It then returns a 301 redirect to the canonical URL while preserving the search string:

Then within the Worker Triggers, I configured a unique route for all of the custom domains, specifically with the fail open option set so it will continue to function even when the free plan daily limits have been reached.

Adding a fail-open route to the Cloudflare Worker.

This will allow the Worker to redirect all incoming requests to the Custom Domains configured in the Pages setup to the canonical URL. When the free plan has been exceeded, it will serve the website from the configured Custom Domain rather than redirect.

Workers can also be bound to custom domains; however, in doing this, when the free quota is exceeded, the Worker will no longer run. This combination of Pages Custom Domains and Worker Routes allows the website to be served indefinitely for free.

Content Redirection

Over time, I have had several landing pages, including ones served from GitHub Pages, which will, by default, expose any other page builds as subdirectories. Some of these became valuable tools used by my friends, so I wanted to preserve them as efficiently as possible. I also wanted to establish a redirect for ‘/blog/’ in case I ever wanted to use it as a subdirectory. Fortunately, Cloudflare Pages support defining server-side redirects in a ‘_redirects’ file:

What’s the Cost

In short, thanks to Cloudflare and Github being incredibly generous with what they consider free, this should cost me a grand total of $0, with the only cost being the domain registration.

Pages within its free tier are limited to 500 builds a month (a build is triggered on every commit) and 100 custom domains which I’ll never reach. The route redirection worker will serve 100k requests for free each day, after which it will fail open, leaving everything functioning, just served from each domain rather than redirected to the canonical domain.

Show Some Flair

When I was first crafting this, I noticed several different glitch effects appearing on the internet, probably because at the time ‘Mr. Robot’ was achieving a lot of well-deserved attention. So I wanted to employ this on the landing page; after a delay, the page would start visibly glitching, leaving people wondering what was happening. At first, I tried to do this with just the ‘clip’ CSS property and ended up with something that was working but not great.

Then I found Codrops’ CSS Glitch Effect, which used the ‘clip-path’ property and was implemented in pure CSS. It was almost perfect for what I wanted to build and was relatively easy to integrate with only a few minor customisations.

Uniquely Me

I’ve traveled with many people, and we usually all have cameras. I was once told that the best pictures of me are always when I’m stopping to look, slow down, take in and appreciate the surroundings. So why not use that as a theme? It turns out “back of head” is an acceptable search term in Google Photos, so I downloaded all of what I considered the best pictures and assembled them into the ‘/bg’ directory.

However, not all pictures are the same; some have me in different positions. To address this, each image is named in the format’ name.background-position.extension’, allowing both the name and the ‘background-position’ CSS property to be extracted by the ‘parsebg.js’ build script.

Involving My Friends

To have fun, I wrote a script js/greetings.js to type out several greetings based on the pluralised “Hello Friends”. The general way the script works is as follows:

  1. It first detects the user’s preferred languages from their web browser.
  2. It then fetches a list of greetings in different languages and fonts from a file named ‘data/greetings.json’.
  3. The script shuffles the list of greetings so that they appear in a random order.
  4. It then moves the greetings that match the user’s preferred languages in ’navigator.languages’ to the front of the list, so they are displayed first. It’s always nicer to greet someone in a language and script that they’re familiar with 😊
  5. The typing animation starts, displaying one greeting at a time. The text appears as if it’s being typed and then gets deleted, one character at a time.
  6. Once a greeting is fully displayed, it pauses briefly before deleting the text.
  7. After deleting the text, it moves on to the following greeting and repeats the process.

This is all built off the file ‘data/greetings.json’, which I gathered from many friends worldwide. I’d ask them how you say “Hello Friends” as a bit of intercultural exchange and talk about how in Australia, we are more prone to say “G’day Mate(s)”. I’d then ask them if I could use it, and slowly I’m building up a collection:

But not all writing scripts are included in the default fonts in a web browser; within ‘greetings.json’, you can define the font for each message which will be automatically fetched in the ‘fetchfonts.js’ build script from Google Fonts. In the current build, I’m using this to download the Noto Fonts and cover Latin, Cyrillic and Greek, CJK, and Arabic are covered, and the Webfont versions are stored locally as a backup if the build script isn’t called or fails.

You can see the final product at https://mitcdh.au

Hiking in Vienna and Lower Austria
Older post

Hiking in Vienna and Lower Austria

Newer post

Is “Cyber Security” Harmful?

Is “Cyber Security” Harmful?