From 225342fd38e33b80179fdbce2457d019efa80e95 Mon Sep 17 00:00:00 2001 From: Brandon Rozek Date: Sat, 28 Dec 2024 08:37:38 -0500 Subject: [PATCH] New Post --- content/blog/implementing-cdn-geodns.md | 42 ++++++++++++++++++ static/files/images/blog/202412252243.png | Bin 0 -> 23182 bytes static/files/images/blog/202412252248.png | Bin 0 -> 248738 bytes .../images/blog/photo_2024-12-25_22-16-17.jpg | Bin 0 -> 41198 bytes 4 files changed, 42 insertions(+) create mode 100644 content/blog/implementing-cdn-geodns.md create mode 100644 static/files/images/blog/202412252243.png create mode 100644 static/files/images/blog/202412252248.png create mode 100644 static/files/images/blog/photo_2024-12-25_22-16-17.jpg diff --git a/content/blog/implementing-cdn-geodns.md b/content/blog/implementing-cdn-geodns.md new file mode 100644 index 0000000..06f7a10 --- /dev/null +++ b/content/blog/implementing-cdn-geodns.md @@ -0,0 +1,42 @@ +--- +title: "Rolling out my own CDN with GeoDNS" +date: 2024-12-28T07:11:16-05:00 +draft: false +tags: [] +math: false +medium_enabled: false +--- + +I noticed when looking at my [monitoring](https://brandonrozek.com/blog/website-status-checking/) that accessing my website from Asia takes almost a full second to load. + +![](/files/images/blog/photo_2024-12-25_22-16-17.jpg) + +I apologize to all my visitors in that segment of the green orb. Please do write to me to tell me you exist though! I'm always happy to hear from readers of my blog. + +> Why don't you use Cloudflare? + +You see friend, I believe in a decentralized web. I want to do my part in not contributing to the monopoly. + +Also, I'm not a huge fan of how most CDNs work. I don't want to have my DNS tied to a CDN provider. + +This gets me thinking, can I roll out my own CDN? It turns out we can! For the purposes of this personal website, we don't need servers in every country in the globe. + +The Internet as we know it, is enabled through many undersea cables. Looking at the [cable map](https://www.submarinecablemap.com/) and the performance timings I have, if I stick a server in Singapore, it should help bring down the load times in Japan and Austrialia as well. + +My website is entirely static. This makes keeping everything in sync simple. I only need to make sure that I have a copy of my website on both servers. + +Luckily, I was able to snag a VPS in Singapore from [GreenCloud](https://greencloudvps.com/) for only $22/year during Black Friday. In New York, at the time of writing I'm using [EasyVM](https://easyvm.net/). + +Now both servers have `nginx` installed and have the files needed to serve my website to visitors. However, if me in New York tries to connect to a server in Singapore, then I'll be the one waiting for 874ms! + +This is where GeoDNS comes in. The DNS server analyzes the IP address of the visitor requesting my websites IP and returns the server that it thinks is the closest! + +Not every DNS provider has this feature. At the time of writing, I'm using [Bunny DNS](https://bunny.net/dns/). The first million queries is free, and then it's $0.30 for every million after that. For the month of December, Bunny has responded to 1,166,405 queries for my domain which luckily doesn't break the bank for me. + +In the DNS zone, I specify the IP addresses of the two servers and include the GPS coordinates of where they sit. If you don't know that information, you can use a website like [ipinfo.io](https://ipinfo.io/) to find out. + +![](/files/images/blog/202412252243.png) + +With my extra server and GeoDNS set up, I now have load times under 350ms in all the regions my monitoring service checks! + +![](/files/images/blog/202412252248.png) diff --git a/static/files/images/blog/202412252243.png b/static/files/images/blog/202412252243.png new file mode 100644 index 0000000000000000000000000000000000000000..153e99eb109a4234b7198f766203cddb045ee4ba GIT binary patch literal 23182 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