loading...
Commons Host

Build your own URL shortener in 15 minutes

sebdeckers profile image Sebastiaan Deckers ・4 min read

The Commons Host CDN platform recently introduced support for custom HTTP response headers and redirect rules. Let's use these features to build our own private URL shortener, with support for a custom domain name and Google Analytics tracking. Did I mention this is all free of charge and 100% open source?

Let's get started.

You could use an existing Commons Host site but this tutorial shows how to get started from scratch. These instructions are intended for Mac OS or Linux.

Project Directory

Start by creating the following project directory structure, then locally installing the Commons Host CLI and short tools with NPM.

short/                 // Project directory
| CNAME                // File
| commonshost.json     // File
| package.json         // File
\ public/              // Directory
  \ redirect/          // Directory
    \ index.html       // File

The project directory is self contained and does not make any global changes to your system. Create it anywhere you prefer, for example in your home directory (~).

Run these commands from a terminal to create the project directory.

$ mkdir -p short/public/redirect
$ cd short
$ touch CNAME commonshost.json public/redirect/index.html
$ npm init -y
$ npm install -D @commonshost/cli @commonshost/short

Domain Name and DNS

Set up your domain name.

Use either a free Commons Host subdomain, or your own registered custom domain name.

Option A) Free *.commons.host subdomain

Edit the CNAME file with your free Commons Host subdomain.

$ echo "your-sub-domain.commons.host" >| CNAME

Replace your-sub-domain.commons.host with any subdomain you like. This tutorial uses short.commons.host, so choose a unique name for your own URL shortening service.

No additional DNS configuration is required with a Commons Host subdomain. The DNS setup for all *.commons.host subdomains already has a wildcard CNAME record pointing to commons.host.

Option B) Custom Domain Name

Edit the CNAME file with your registered custom domain name.

$ echo "your-name.example" >| CNAME

Replace your-name.example with your actual registered custom domain name.

You must also create a CNAME record pointing from your-name.example to commons.host at your DNS provider's dashboard. That CNAME record will direct users to their nearest Commons Host edge server.

Note: With Cloudflare DNS you may encounter a redirect loop when using Flexible SSL (the default setting). Commons Host enforces full TLS and never serves unencrypted content. To solve this you can either:

  • Disable the Cloudflare CDN for your CNAME record by setting: DNS > DNS Records > Status > DNS Only
  • Or, leave the Cloudflare CDN enabled but configure the setting: Crypto > SSL > Full SSL

Configuration File

Save this JSON boilerplate as: commonshost.json

This contains the necessary custom header rule and a placeholder for the URL redirects.

{
  "hosts": [
    {
      "headers": [
        {
          "uri": "/redirect/{?url,}",
          "fields": {
            "Refresh": "2; {url}"
          }
        }
      ],
      "redirects": []
    }
  ]
}

Redirect Page

Save this HTML boilerplate as: public/redirect/index.html

To set up Google Analytics replace GA_TRACKING_ID in the code below with your Google Analytics tracking ID (e.g. UA-12345678-1). See the Google Analytics documentation for details.

Feel free to customise or remove any Commons Host branding. You have full control over your website.

<!DOCTYPE html>
<html>
  <head>
    <script async src="https://www.googletagmanager.com/gtag/js?id=GA_TRACKING_ID"></script>
    <script>
      window.dataLayer = window.dataLayer || []
      function gtag(){dataLayer.push(arguments)}
      gtag('js', new Date())
      gtag('config', 'GA_TRACKING_ID')
    </script>
    <title>Redirecting</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
      body { text-align: center; font-family: sans-serif; }
      a { color: black; }
    </style>
  </head>
  <body>
    <main>
      <h1>Redirecting</h1>
      <p id="location"></p>
    </main>
    <footer>
      Powered by πŸ‘ <a href="https://commons.host" rel="noopener">Commons Host</a>.
    </footer>
    <script>
      if ('URLSearchParams' in window) {
        const params = new URLSearchParams(location.search)
        if (params.has('url')) {
          const to = document.createElement('a')
          const url = params.get('url')
          to.href = url
          to.textContent = url
          document.querySelector('#location').appendChild(to)
        }
      }
    </script>
  </body>
</html>

Sign Up to Commons Host

Create a Commons Host account via the CLI tool. This saves a token in ~/.commonshost that keeps you authenticated on this machine.

$ npx commonshost signup

Enter an email address, username, and password to create your account.

? Email address: sebdeckers83@gmail.com
? Username: seb
? Password: [hidden]
  βœ” Registering account
  βœ” Creating new authentication token
  βœ” Saving credentials

Shorten a URL

The short command creates a new redirect rule and prints the resulting short URL.

$ npx short https://en.wikipedia.org/wiki/Longest_words
πŸ”— https://short.commons.host/1302

The redirects section of your commonshost.json configuration file should now contain something like this:

"redirects": [
  {
    "from": "/1302",
    "to": "/redirect/?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FLongest_words"
  }
]

Tip: Run npx short --help to see more advanced options. For example the --emoji option will generate random emoji for shortened URLs. 🀨

Deploy to Commons Host

$ npx commonshost deploy
To cancel, press Ctrl+C.

Detected options file: commonshost.json
To override, use: --options "path"

Deploying:

  Directory:    ~/short
  File count:   1
  Total size:   1.84 kB
  URL:      https://short.commons.host
  Options:  ~/short/commonshost.json

  βœ” Uploading

Finished! Enjoy your personal URL shortener powered by Commons Host.

Summary

To shorten another URL, just repeat the final two commands from within the project directory:

  1. npx short https://some.really.long.url.example/foo/bar.html
  2. npx commonshost deploy --confirm

Check the server documentation to learn how to customise your Commons Host site further, like setting up a 404 fallback HTML page.

Thanks to @donavon for the feedback on this tutorial.

Discussion

pic
Editor guide
Collapse
craigz profile image
craigz

this is great and it 'works' inso as much as locally issuing the command 'npx short [URL]' generates a lovely shortened link using my custom domain, which it does write into the commonshost.json file. however, that link is unusable as attempts to connect to the url fail whichever browser i use. the cname for my custom domain is configured and working from the command line (it resolves to commons.host). deploying the site reports success although it also throws the following error: "(node:12208) [DEP0135] DeprecationWarning: ReadStream.prototype.open() is deprecated"

so as it stands, i have a nice framework and an npx command, but really in terms of doing anything with this, am unable to do so. i'm trying to wrap my head around the docs at commonshost, but lining up their default install with what's going on here with the redirects is not making a load of sense.

i'd be open to any suggestions as i'd love to move forward with this as a shortener and not be required to mess with php as most of the self hosted options seem to be using. i'm also not interested in using bit.ly as a backend.

thanks for an interesting start at least!

Collapse
sebdeckers profile image
Sebastiaan Deckers Author

Hey, could you tell me the domain name you're using? Might be a DNS or TLS certificate issue.

Finally got around to looking into the short tool. Refactored its code and added unit/regression tests. I also fixed that deprecation warning in the deploy tool. Just verified that it works on my machineℒ️. πŸ˜…

Will take a look at editing the Commons Host docs. Right now it's partly my own docs to configure the CDN platform, mixed in with docs for users of the various offered services (CDN, static hosting, DNS over HTTPS, even a Gopher client and proxy 😝).

Collapse
craigz profile image
craigz

hey, thanks for getting back to me!

after reading your comment i reviewed my notes and app from back then and gave it all another try and this time around things seem to work just fine. additionally, i've updated short to version 5.1.0 and sure enough, no more deprecation warning. most excellent. so i've got a working cli shortener.

now that it's working of course i want to take it further, i saw in another comment the link to the api which is exciting. i'm not entirely certain how to work with it, but i've started by installing @commonshost/short as a dev-dependency in a new project. i'm going to hack on this some over the weekend.

Collapse
sebdeckers profile image
Sebastiaan Deckers Author

Thanks for the bug report. πŸ™‡πŸΌβ€β™‚οΈ I'll take a look to see what needs to be updated in this blog post.

Collapse
philsmy profile image
Phil Smy

Nice...but how to do this programmatically? having a manual link shortener (that you call from the command line!) isn't THAT useful!

Collapse
sebdeckers profile image
Sebastiaan Deckers Author

Thanks for the useful suggestion. An API for short is now available: gitlab.com/commonshost/short#api

This tool started as a simple demo showcase but quite a few people seem to be looking for this type of solution. I'm happy to make it more useful if you provide more feedback.

Collapse
greenwichmytime profile image
GreenwichMyTime

Hi

Any examples of anybody deploying this for their own url shortener?

Collapse
sebdeckers profile image
Sebastiaan Deckers Author

I've received emails with tech questions from a few people. No idea how many are really using it, or how much traffic they see. I remember @donavon tried it briefly, but not sure if that was continued.

Collapse
casacode profile image
Brian Liotti

InternalServerError: ENOSPC: no space left on device, write

bummer

Collapse
sebdeckers profile image
Sebastiaan Deckers Author

Had some issues with flaky, large deployments causing the scratch space on the Commons Host core API server to fill up and never get cleared until a reboot. I fixed a few bugs recently that should prevent those problems from recurring. (See: gitlab.com/commonshost/support/iss...)