I think ... - url-shortenerhttps://blog.kmonsoor.com/2021-06-06T00:00:00+06:00Create a free go-link server “on edge” using Cloudflare Worker KV2021-06-06T00:00:00+06:002021-06-06T00:00:00+06:00Khaled Monsoortag:blog.kmonsoor.com,2021-06-06:/golink-server-using-cloudflare-worker-kv/<p>Among quite a few ways to implement a go-link server (i.e., url-forwarder, short-url server, etc.), I will show how to use free-tier Cloudflare Worker (& <span class="caps">KV</span>) to create an in-house, on-edge, <strong>no-webserver</strong> go-link server.</p><p>Among quite a few ways to implement a go-link server (i.e., url-forwarder, short-url server, etc.), I’m going to show you how to use free-tier Cloudflare Worker (& <span class="caps">KV</span>) to create an in-house, on-edge, <strong>no-webserver</strong> go-link server.</p>
<p>For example, the short-link for this article is <a href="https://go.kmonsoor.com/golink-kv">go.kmonsoor.com/golink-kv</a> </p>
<p><img alt="overall structure" src="https://i.imgur.com/MjIS5gD.png"></p>
<ul>
<li><code>/latest</code> (by which I mean <code>go.yourdomain.co/latest</code>) may point to <code>https://www.yourcompany.com/about/news</code> which is a public page</li>
<li><code>/hr-help</code> may point to <code>https://www.company-internal.com/long-link/hr/contact.html</code>, which is company’s internal human-resources help portal</li>
<li><code>/cnypromo</code> may point to <code>https://shop.yourcompany.com/sales/promotions/?marketing-promo=2021-cny</code> which is a temporary sales promotions page targeting the shoppers during the Chinese new year of 2021.</li>
</ul>
<p>Please note that using the setup and the code below, it’ll be possible to resolve short-links via a <strong>single</strong> sub-domain, e.g., <code>go.your-domain.co</code>. However, it’s possible (with some modification of the code) to resolve/redirect via <em>any number of domains</em> (your own, of course) towards any other public or private <span class="caps">URL</span>, and all sorts of novelties. However, for brevity’s sake, I will discuss the first one, a single sub-domain usecase.</p>
<p>To set up a go-link server or short-<span class="caps">URL</span> resolver via a proper <span class="caps">KV</span>+Worker combination, we’ll go through these steps:</p>
<div class="toc">
<ul>
<li><a href="#pre-requisites">Pre-requisites</a></li>
<li><a href="#create-the-short-link-map-as-a-kv">Create the short-link map as a <span class="caps">KV</span></a></li>
<li><a href="#mapping-a-kv-to-a-worker-variable">Mapping a <span class="caps">KV</span> to a Worker variable</a></li>
<li><a href="#handling-a-route-with-webworker">Handling a route with webworker</a></li>
<li><a href="#create-the-worker">Create the Worker</a></li>
<li><a href="#pointing-a-dns-record-to-the-worker">Pointing a <span class="caps">DNS</span> record to the Worker</a></li>
<li><a href="#next-step">Next step</a></li>
<li><a href="#related">Related</a></li>
</ul>
</div>
<h1 id="pre-requisites">Pre-requisites<a class="headerlink" href="#pre-requisites" title="Permanent link">¶</a></h1>
<ul>
<li>The <span class="caps">DNS</span> resolver for the <strong>root</strong> domain (in the example below, <em><code>kmonsoor.com</code></em>) needs to be Cloudflare. Because the core of the solution, the “worker”, runs on the nearest (from the user) edge of Cloudflare using a standard <span class="caps">KV</span> (“key, value”) list.</li>
<li>Write permission to the <span class="caps">DNS</span> configuration as you’d need to add a new <span class="caps">AAAA</span> <span class="caps">DNS</span> record.</li>
<li>Some knowledge of Javascript(<code>ES6</code>), as we are going to write the “worker” in that language.</li>
</ul>
<h1 id="create-the-short-link-map-as-a-kv">Create the short-link map as a <span class="caps">KV</span><a class="headerlink" href="#create-the-short-link-map-as-a-kv" title="Permanent link">¶</a></h1>
<p>We’ll start the setup by creating the short-link map, the list between the short-link segments that you (or someone in your org) define, and the actual URLs they need to point to.</p>
<p>Find the <span class="caps">KV</span> stuff in the <code>Workers</code> section. From the screenshot, please ignore the “Route” section for now. </p>
<p><img alt="Find the KV stuff in the Workers section" src="https://i.imgur.com/b2Rk45u.png"></p>
<ul>
<li>you’d need to create a Worker <span class="caps">KV</span> “Namespace”. Name the namespace as you seem fit. I named it <code>REDIRECTS</code> (in all caps just as a convention, not required). </li>
<li>List the short links <span class="amp">&</span> their respective target URLs. From the examples in the intro, the keys <code>latest</code>, <code>hr-help</code>, <code>cnypromo</code> etc. would be in as the “key”, and the target full links as the respective “value”.</li>
<li>Remember <span class="caps">NOT</span> to start the short part with ‘/’. It’ll be taken care of in the code.</li>
</ul>
<p><img alt="Create the short-link map as a KV" src="https://i.imgur.com/jkC8bSr.png"></p>
<p>Once you’ve listed all your desired (short-link, target-link) combinations, now we have a <span class="caps">KV</span> on Cloudflare. However, it’s not referencable from your Worker code, not yet. Hence the next step.</p>
<h1 id="mapping-a-kv-to-a-worker-variable">Mapping a <span class="caps">KV</span> to a Worker variable<a class="headerlink" href="#mapping-a-kv-to-a-worker-variable" title="Permanent link">¶</a></h1>
<p>Now, we will map the previously created <span class="caps">KV</span> to a variable that can be referenced from our Worker code. Please note that though I used different names, it can be the same as well. Also, note that multiple Workers can access a single <span class="caps">KV</span>, and vice versa is also true; a single Worker can reference multiple KVs.</p>
<p><img alt="Mapping a KV to a Worker variable" src="https://i.imgur.com/lb7G9si.png"></p>
<h1 id="handling-a-route-with-webworker">Handling a route with webworker<a class="headerlink" href="#handling-a-route-with-webworker" title="Permanent link">¶</a></h1>
<p><img alt="Handling a route with webworker" src="https://i.imgur.com/KohHRfR.png"></p>
<h1 id="create-the-worker">Create the Worker<a class="headerlink" href="#create-the-worker" title="Permanent link">¶</a></h1>
<p>Now, we will write Worker-code that runs on <code>V8</code> runtime on the nearest (from the requesting user) “edge” location of Cloudflare, to execute the code and deliver the result(s) to the user. In this case, that would be to redirect user-requested address to the mapped one (by you, in the <span class="caps">KV</span> namespace above).</p>
<p><img alt="Creating a worker" src="https://i.imgur.com/eNfZNyN.png"></p>
<p>The code editor looks like this: </p>
<p><img alt="The code editor for Cloudflare worker" src="https://i.imgur.com/pb9AE9v.png"></p>
<p>If you rather prefer to copy-paste, please feel free to do it from the below GitHub Gist.</p>
<div class="gist">
<script src="https://gist.github.com/kmonsoor/dc9f96660423c96471f8574ba018d867.js"></script>
</div>
<p>Once done, it should look like …
<img alt="created webworker" src="https://i.imgur.com/XSdKB56.png"></p>
<h1 id="pointing-a-dns-record-to-the-worker">Pointing a <span class="caps">DNS</span> record to the Worker<a class="headerlink" href="#pointing-a-dns-record-to-the-worker" title="Permanent link">¶</a></h1>
<p>Finally, we need to point a <span class="caps">DNS</span> record that’ll redirect all requests to your re-soutign sub-domain (e.g. <code>go.your-domain.com</code>) to the Cloudflare Worker that we just created.</p>
<p>According to the Cloudflare docs, the <span class="caps">DNNS</span> record must be an <span class="caps">AAAA</span> record, pointing to the IPv6 address <code>100::</code>. The “Name” here is the “sub-domain” part of your choice, which is better be short, to rightfully serve our goal here. </p>
<p><img alt="Pointing a DNS record to it" src="https://i.imgur.com/62bk7pe.png"></p>
<p>Voila ! Now, test some of the short-urls that you’ve mapped via the <span class="caps">KV</span>. Enjoy !
Watch out for the target usage though. <a href="https://developers.cloudflare.com/workers/platform/limits#worker-limits">Here’s the limit</a>. </p>
<p>I think you’ll be fine, unless you’re some celebrity ;)</p>
<h1 id="next-step">Next step<a class="headerlink" href="#next-step" title="Permanent link">¶</a></h1>
<p>As the next step, I’m thinking to create a generic <code>Go/Link</code> resolver browser extension. Then, someone can set their own default domain or company domain of choice as short-domain host. In that case, entering just <code>go/hr-help</code> on the browser will take to <code>https://www.company-internal.com/.../hr/contact.html</code> that we have discussed at the beginning (remember the example case of an internal human resources help portal?).</p>
<h1 id="related">Related<a class="headerlink" href="#related" title="Permanent link">¶</a></h1>
<p>If you want to do this url-direction <strong>on your server, but only using webserver</strong>, try this: <a href="https://go.kmonsoor.com/golink-caddy">Personal short-link server using only Caddyserver</a></p>
<hr>
<p>If you find this post helpful, you can show your support <a href="https://www.patreon.com/kmonsoor">through Patreon</a> or by <a href="https://ko-fi.com/kmonsoor">buying me a coffee</a>. <em>Thanks!</em></p>Deploying a short-link aka go-link server using only Caddyserver2021-04-16T00:00:00+06:002021-04-16T00:00:00+06:00Khaled Monsoortag:blog.kmonsoor.com,2021-04-16:/deploying-golink-server-using-Caddy/<p>Yeah, there are tons of open-source, full-fledged link-shorteners. But, none were exactly what I wanted. Hence, the minimal approach only by utilizing an amazing webserver, <code>Caddy</code>. Here we go …</p><p>Before I go into any details, please note that I’ve used the term “shortlink-server” instead of “url-shortener” because the difference is significant for this post.
A url-shortener takes a long url, and gives a short url, then redirects any requests for the shortened link to its longer counterpart. On the contrary, shortlink-server takes both the long and short url as inputs, then only does the redirect-ion part.</p>
<h2 id="backstory">Backstory<a class="headerlink" href="#backstory" title="Permanent link">¶</a></h2>
<p>If I wanted a fantastic, personal url-shortener or “go link” server, there are many excellent solutions out there, which are not only free or open-source but full-fledged as well for personal or public usage. Instead, I wanted some “service” that would “resolve” my personal, short links. I have been using bit.ly for a long time for its customizable “short-half” part, but the problem with bit.ly is – for some God-forsaken reason – blocked by the Bangladeshi govt. So, I needed a replacement to be appropriately “glocal”.
There are many free (unbranded) and commercial (branded) options as well, but I wanted something that would be resolved via my hosted service (and personal domain) and as cheap as possible. So, basically solution for a poor nerd :D</p>
<p>Before jumped into this solution, I tried (deployed <span class="amp">&</span> tested) few others myself, mainly <a href="https://github.com/kellegous/go">kellegous/go</a>, <a href="kutt.it">kutt.it</a> and <a href="https://github.com/adamyi/golinks">adamyi/golinks</a>. But, all of them “too featureful” for my needs.</p>
<p><img alt="Simple, on-prem short-link server using Caddy webserver" src="https://i.imgur.com/4nZbnUE.png"></p>
<p>What I wanted is to be able to:</p>
<ul>
<li>resolve only my custom shortlinks (hence, no need for url-shortener)</li>
<li>not a public, internet-facing service (hence, any frontend, authentication, email verification etc. would be overkill )</li>
<li>minimal setup (if possible, no webapp at all)</li>
</ul>
<p>Given my previous experience with <code>Caddy</code> webserver, which is an amazing one(<a href="https://caddyserver.com/docs/">why?</a>), I had a gut feeling that Caddy has something for me – under the sleeve – to meet my minimal set of requirements. Thankfully, I managed to find it.</p>
<p>I believe <span class="caps">NGINX</span>, currently the most popular webserver, has some kind of similar mechanism as well. But, I’m not an expert, and once I was genuinely intimidated by its config file syntax. <span class="caps">YMMV</span>.</p>
<h2 id="what-you-gonna-need">What you gonna need?<a class="headerlink" href="#what-you-gonna-need" title="Permanent link">¶</a></h2>
<ul>
<li>your own domain which will be the root of the shortlinks. While sub-domained <span class="caps">URL</span> like <code>go.company-name.com/*</code> is quite common, if you have some short domain, like you.co/*, only for this purpose, that’s fine as well.</li>
<li>A web-host server or public-facing instance with its own, <strong>public IPv4 address</strong>.</li>
<li>working knowledge of Linux</li>
</ul>
<h2 id="step-1-point-your-subdomain-to-the-right-place">Step-1: Point your subdomain to the right place<a class="headerlink" href="#step-1-point-your-subdomain-to-the-right-place" title="Permanent link">¶</a></h2>
<ul>
<li>Find out what’s the <strong>puplic IPv4 address</strong> of your instance that’ll act as the webserver. It’s usually on the cloud management dashboard.</li>
<li>make sure that, regardless of your cloud architecture (e.g. <span class="caps">VPC</span>, subnet, firewall etc.), the <span class="caps">SSL</span> port (<code>:443</code>) of the instance is reachable from the public internet.</li>
<li>now go to your domain name registrar (or, <span class="caps">DNS</span> management provider which in my case is Cloudflare). There, you need to point shortlink subdomain (<code>go.</code>)to the webserver’s <span class="caps">I.P.</span> address. In <span class="caps">DNS</span> terms, you’ll be creating a <span class="caps">CNAME</span> entry on the domain’s nameserver table.</li>
</ul>
<p>You can do this step as the last one. But for some reason, I prefer it to do first. Because sometimes, <a href="https://blog.cloudflare.com/never-deal-with-dns-propagation-again/"><span class="caps">DNS</span> propagation</a> takes some time. But, once my web service is up and running, I like to see the result instantaneously. ;)</p>
<h2 id="step-2-install-caddy-a-mighty-webserver">Step-2: Install Caddy, a mighty webserver<a class="headerlink" href="#step-2-install-caddy-a-mighty-webserver" title="Permanent link">¶</a></h2>
<p>Depending on your host <span class="caps">OS</span> (Ubuntu 20.04 <span class="caps">LTS</span> in my case), you need to <a href="https://caddyserver.com/docs/install">install the <code>Caddy</code> webserver</a>. While there are some hacky solutions to run, I think running <code>Caddy</code> as a background service is the simplest to manage.
In fact, the documentation of Caddy is excellent, so I’d better leave that part to you.</p>
<p>After running with the default config(<code>Caddyfile</code>), (in Ubuntu’s case, located as <code>/etc/caddy/Caddyfile</code>), it should show a status somewhat like the below image. Please note that, in many cases, if running without <code>sudo</code>, Caddy cannot attach itself with the <span class="caps">SSL</span> port (<code>:443</code>), which is necessary for serving <code>https://</code>. So, check for that error message in the “status” log.</p>
<p><img alt="Caddy service on Ubuntu" src="https://i.imgur.com/cfS5nvZ.png?1"></p>
<p><em><strong><span class="caps">PS</span>:</strong> By the way, want your console and command prompt to look 🚀 like mine? Here’s the guide: <a href="https://blog.kmonsoor.com/pimp-up-my-terminal/">How do I pimp up my terminal on Linux</a></em></p>
<h2 id="step-3-tell-caddy-your-short-links-to-redirect">Step-3: Tell Caddy your short-links to redirect<a class="headerlink" href="#step-3-tell-caddy-your-short-links-to-redirect" title="Permanent link">¶</a></h2>
<p>Now, it’s time to configure Caddy to actually do the job.</p>
<p>Caddy has its native <code>redir</code> <span class="dquo">“</span>directive” to redirect incoming web-request from one to another. While the <code>map</code> directive is relatively new, it makes the config file, i.e., Caddyfile, look elegant in case you have (or will have in the long run) a long list of short-links.</p>
<p>Here’s mine, which is working nicely … </p>
<div class="highlight"><pre><span></span><code><span class="linenos" data-linenos=" 1 "></span># /etc/caddy/Caddyfile
<span class="linenos" data-linenos=" 2 "></span>
<span class="linenos" data-linenos=" 3 "></span>go.kmonsoor.com { # replace it your web-url root
<span class="linenos" data-linenos=" 4 "></span>
<span class="linenos" data-linenos=" 5 "></span> map {path} {redirect-uri} {
<span class="linenos" data-linenos=" 6 "></span> /blog https://blog.kmonsoor.com
<span class="linenos" data-linenos=" 7 "></span> /photos https://photos.kmonsoor.com
<span class="linenos" data-linenos=" 8 "></span>
<span class="linenos" data-linenos=" 9 "></span> /resume https://drive.google.com/file/d/1nMS3i1ai6nsI70zZ7NFnNQ_XmvAa4GOl
<span class="linenos" data-linenos="10 "></span> /resume-doc https://docs.google.com/document/d/1ECx1Yr8Jzz9I3S5VcoKnZQz56oIht2XaM5gSNetcWag
<span class="linenos" data-linenos="11 "></span>
<span class="linenos" data-linenos="12 "></span> /rickrolled https://www.youtube.com/watch?v=dQw4w9WgXcQ
<span class="linenos" data-linenos="13 "></span>
<span class="linenos" data-linenos="14 "></span> # will add new ones here like the above
<span class="linenos" data-linenos="15 "></span> # ...
<span class="linenos" data-linenos="16 "></span> }
<span class="linenos" data-linenos="17 "></span>
<span class="linenos" data-linenos="18 "></span> # this below code is required to actually make the above `map` work
<span class="linenos" data-linenos="19 "></span>
<span class="linenos" data-linenos="20 "></span> @hasRedir expression `{redirect-uri} != ""`
<span class="linenos" data-linenos="21 "></span> redir @hasRedir {redirect-uri}
<span class="linenos" data-linenos="22 "></span>
<span class="linenos" data-linenos="23 "></span> # code below is to set the default response if the requested shortlink isn't here
<span class="linenos" data-linenos="24 "></span> respond "Thas's an unknown short URL ... :("
<span class="linenos" data-linenos="25 "></span>}
</code></pre></div>
<p>Note: Don’t forget to restart the <code>caddy</code> service to let the new config to take effect.</p>
<h2 id="step-4-profit">Step-4: Profit<a class="headerlink" href="#step-4-profit" title="Permanent link">¶</a></h2>
<p>Yeah, that’s it. Now, add some own personal stuff with some cool short-links, and proudly share with the world.</p>
<h2 id="whats-next">What’s next ?<a class="headerlink" href="#whats-next" title="Permanent link">¶</a></h2>
<p>I’m thinking that given the very low workload my shortlink resolver needs — unless I’m becoming an overnight internet sensation — using a server instance only for this purpose is overkill. My next goal is to have the same service using some “serverless” function or using the “<a href="https://developers.cloudflare.com/workers/examples/redirect">worker on the edge</a>” thing from Cloudflare. Let’s see ;)</p>
<p><strong>Update</strong> Now, actually done it. Here is the link: <a href="https://blog.kmonsoor.com/golink-server-using-cloudflare-worker-kv/">Free short-link server “on edge” using Cloudflare Worker <span class="caps">K.V.</span></a></p>
<hr>
<p>If you find this post helpful, you can show your support <a href="https://www.patreon.com/kmonsoor">through Patreon</a> or <a href="https://paypal.me/KhaledMonsoor/">Paypal</a> or by <a href="https://ko-fi.com/kmonsoor">buying me a coffee</a>. <em>Thanks!</em></p>