Content Delivery Networks (CDNs) are used on websites and applications primarily to speed up the loading of static elements. This is achieved by caching files on CDN servers located in different geographical regions. When a user requests data through a CDN, they receive it from the nearest server.
The operation principle and functionality of all content delivery networks are roughly the same. Upon receiving a request to load a file, the CDN server will temporarily fetch it from the original server and deliver it to the user, caching it for a specified time. For all subsequent requests, the response is delivered from the cache. All CDNs have options for preloading files, clearing caches, setting cache retention periods, and much more.
Sometimes, for various reasons, it is necessary to set up your own content delivery network, and then — let there be a guide to assembling another bicycle.

Source:
When You Need Your Own CDN
Let's consider the cases when launching your own CDN makes sense:
- when there is a desire to save money, while current expenses even when using inexpensive CDNs like amount to several hundred dollars a month
- if we want to have a permanent cache or a cache without neighbors on the server and channel
- there are no points of presence in your desired region from CDN services
- special content delivery settings are required
- if we want to speed up the delivery of dynamic content by placing production servers closer to users
- there are concerns that a third-party CDN service might improperly gather or use information about user behavior (hello to services that are not GDPR-compliant) or engage in other improper actions
In most other cases, it is more reasonable to use existing ready-made solutions.
What You Need to Launch
It's great if you have your own Autonomous System (AS). With it, you can assign the same IP to multiple servers and direct users to the nearest one at the network level. It's worth noting that even with a block of addresses /24, it is possible to build a content delivery network. Some server providers allow announcements for use in all available regions.
If you are not the lucky owner of a block of IP addresses, to set up a simple CDN you will need:
- a domain name or subdomain
- at least two servers in different regions. The server can be either dedicated or virtual
- a geoDNS tool. This allows users accessing the domain to be directed to the nearest server
Register the domain and order servers
The domain registration is straightforward — register in any zone with any registrar. You can also use a subdomain for the CDN, like something such as cdn.yourdomain.com. In our example, we will proceed this way.
As for ordering servers — they should be rented in the regions and countries where your user base is located. If the project is intercontinental, it's convenient to choose hosting providers that offer servers worldwide. Examples include: , and — for dedicated servers, and — for virtual cloud servers*.
For our private CDN, we will order 3 virtual servers on different continents. On Vultr one server for $5/month we will get 25GB SSD space and 1TB of traffic. During installation, we will choose the latest Debian. Our servers:
Stockholm, ip: 199.247.18.199
Chicago, ip: 149.28.121.123
Singapore, ip: 157.230.240.216
* Vultr and DigitalOcean promise $100 credit for users who register through the links in this article, immediately after adding a payment method. The author also receives a small compliment from this, which is quite significant for him right now. Please be understanding.
Setting up geoDNS
For users accessing the CDN domain or subdomain to be directed to the correct (nearest to them) server, we will need a DNS server with geoDNS functionality.
The principle and order of operations for geoDNS are as follows:
- It determines the IP of the client that sent the DNS request, or the IP of the recursive DNS server used when processing the client's request. These recursive servers are usually DNS servers of the providers.
- Based on the client's IP, it identifies their country or region. For this, GeoIP databases are used, of which there are plenty today. There are some decent .
- Depending on the client's location, it returns the IP address of the nearest CDN server.
A DNS server with geoDNS functionality can be , but it’s better to use ready-made solutions with a network of DNS servers around the world and out of the box:
- from $9.95/month, GeoDNS tariff, there is one DNS Failover by default
- from $25/month, includes DNS Failover
- from $35/month for 50M clean geo-queries. DNS Failover is billed separately
- from $125/month, with 10 DNS Failover
- , the 'Geo Steering' feature is available in Enterprise plans
When ordering geoDNS, pay attention to the number of queries included in the plan, and keep in mind that the actual number of queries to the domain may greatly exceed expectations. Millions of bots, scanners, spammers, and other unwanted entities operate tirelessly.
Almost all DNS services include the essential service for building a CDN — DNS Failover. It allows you to monitor the operation of your servers and automatically replace the address of a non-working server with a backup in the DNS responses if there are no signs of life.
To build our CDN, we will use , GeoDNS plan.
We will add a new DNS zone in the personal account by specifying our domain. If we are building the CDN on a subdomain and the main domain is already in use, don't forget to add the existing working DNS records immediately after adding the zone. The next step is to create several A records for the CDN domain/subdomain, each of which will apply to the region we specify. Regions can be continents or countries, with subregions available for the USA and Canada.
In our case, the CDN will be set up on the subdomain cdn.sayt.in. After adding the zone sayt.in, we will create the first A record for the subdomain and direct all of North America to the server in Chicago:

We will repeat this action for other regions, making sure to create one record for default regions as well. Here's what the final setup will look like:

The last default record in the screenshot means that all unspecified regions (such as Europe, Africa, satellite internet users, etc.) will be directed to the server in Frankfurt.
This completes the basic DNS setup. The last step is to go to the domain registrar's website and replace the current NS records of the domain with those provided by ClouDNS. While the NS records are updating, we will prepare the servers.
Installing SSL certificates
Our CDN will operate over HTTPS, so if you already have SSL certificates for the domain or subdomain, upload them to all servers, for example, to the directory /etc/ssl/вашдомен/
If you don't have certificates, you can obtain a free one from Let’s Encrypt. The The client is convenient and easy to set up, and most importantly, it allows domain/subdomain validation via DNS through the ClouDNS API.
We will install acme.sh only on one server—the European server 199.247.18.199, and certificates will be copied from it to all others. To install, we will execute:
root@cdn:~# wget -O - https://get.acme.sh | bash; source ~/.bashrcDuring the installation of the script, a CRON job will be created for the further update of certificates without our involvement.
Domain verification when issuing the certificate will be done via DNS using the API, so in the ClouDNS personal cabinet in the Reseller API menu, you need to create a new API user and set a password for it. The obtained auth-id with the password should be written in the file ~/.acme.sh/dnsapi/dns_cloudns.sh (do not confuse with the file dns_clouddns.sh). Here are the lines that need to be uncommented and edited:
CLOUDNS_AUTH_ID=
CLOUDNS_AUTH_PASSWORD=""
Now we will request an SSL certificate for cdn.sayt.in
root@cdn:~# acme.sh --issue --dns dns_cloudns -d cdn.sayt.in --reloadcmd "service nginx reload"In the parameters, we included a command for automatically reloading the web server configuration after each renewal of the certificate in the future.
The entire process of obtaining the certificate may take up to 2 minutes; do not interrupt it. If a domain validation error occurs, try running the command again. In the end, we will see where the certificates were uploaded:

Remember these paths; they will need to be specified when copying the certificate to other servers, as well as in the web server settings. Do not worry about the Nginx config reload error; there will be none on a fully configured server when renewing certificates.
All that remains for us regarding SSL is to copy the obtained certificate to two other servers, preserving the path to the files. We will create the same directories on each of them and make a copy:
root@cdn:~# mkdir -p /root/.acme.sh/cdn.sayt.in/
root@cdn:~# scp -r root@199.247.18.199:/root/.acme.sh/cdn.sayt.in/* /root/.acme.sh/cdn.sayt.in/
To ensure regular certificate updates, we will create a daily CRON job on both servers with the command:
scp -r root@199.247.18.199:/root/.acme.sh/cdn.sayt.in/* /root/.acme.sh/cdn.sayt.in/ && service nginx reload
At this time, access to the remote source server must be configured , i.e., without entering a password. Do not forget to do this.
Installation and configuration of Nginx
To serve static content, we will use Nginx configured as a caching proxy server. We will update the package lists and install it on all three servers:
root@cdn:~# apt update
root@cdn:~# apt install nginxInstead of the default, we will use the configuration from the spoiler below:
nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 4096;
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log off;
error_log /var/log/nginx/error.log;
gzip on;
gzip_disable "msie6";
gzip_comp_level 6;
gzip_proxied any;
gzip_vary on;
gzip_types text/plain application/javascript text/javascript text/css application/json application/xml text/xml application/rss+xml;
gunzip on;
proxy_temp_path /var/cache/tmp;
proxy_cache_path /var/cache/cdn levels=1:2 keys_zone=cdn:64m max_size=20g inactive=7d;
proxy_cache_bypass $http_x_update;
server {
listen 443 ssl;
server_name cdn.sayt.in;
ssl_certificate /root/.acme.sh/cdn.sayt.in/cdn.sayt.in.cer;
ssl_certificate_key /root/.acme.sh/cdn.sayt.in/cdn.sayt.in.key;
location / {
proxy_cache cdn;
proxy_cache_key $uri$is_args$args;
proxy_cache_valid 90d;
proxy_pass https://sayt.in;
}
}
}In the config, we will edit:
- max_size — the cache size should not exceed available disk space
- inactive — the time for storing cached data that has not been accessed by anyone
- ssl_certificate and ssl_certificate_key — paths to the SSL certificate and key files
- proxy_cache_valid — the duration for storing cached data
- proxy_pass — the address of the original server from which the CDN will request files for caching. In our example, this is sayt.in
As we can see, everything is straightforward. The only complexity may arise in configuring the caching time due to the similarity of directives. inactive and proxy_cache_validLet's break them down using our example. Here's what happens with inactive=7d and proxy_cache_valid 90d:
- if the request is not repeated within 7 days, the data will be removed from the cache after this period
- if the request is repeated at least once in 7 days, the cached data will be considered stale after 90 days, and upon the next request, Nginx will refresh it from the original server
After finishing the edits nginx.conf, we will reload the configuration:
root@cdn:~# service nginx reloadOur CDN is fully ready. For $15/month, we received points of presence on three continents and 3 TB of traffic: 1 TB at each location.
Checking CDN operation
Let's take a look at the pings to our CDN from different geographical locations. Any ping services will do.
Launch Point
Host
IP
Avg time, ms
Germany, Berlin
cdn.sayt.in
199.247.18.199
9.6
Netherlands, Amsterdam
cdn.sayt.in
199.247.18.199
10.1
France, Paris
cdn.sayt.in
199.247.18.199
16.3
United Kingdom, London
cdn.sayt.in
199.247.18.199
14.9
Canada, Toronto
cdn.sayt.in
149.28.121.123
16.2
USA, San Francisco
cdn.sayt.in
149.28.121.123
52.7
USA, Dallas
cdn.sayt.in
149.28.121.123
23.1
USA, Chicago
cdn.sayt.in
149.28.121.123
2.6
USA, New York
cdn.sayt.in
149.28.121.123
19.8
Singapore
cdn.sayt.in
157.230.240.216
1.7
Japan, Tokyo
cdn.sayt.in
157.230.240.216
74.8
Australia, Sydney
cdn.sayt.in
157.230.240.216
95.9
The results are good. We will now place a test image at the root of the main site. test.jpg and check its loading speed through the CDN. It has been said, — . Content is delivered quickly.
We will write a small script in case we want to clear the cache at the CDN point.
purge.sh
#!/bin/bash
if [ -z "$1" ]
then
echo "Purging all cache"
rm -rf /var/cache/cdn/*
else
echo "Purging $1"
FILE=`echo -n "$1" | md5sum | awk '{print $1}'`
FULLPATH=/var/cache/cdn/${FILE:31:1}/${FILE:29:2}/${FILE}
rm -f "${FULLPATH}"
fi
To remove all the cache, you just need to run it; a separate file can be cleared like this:
root@cdn:~# ./purge.sh /test.jpgInstead of conclusions
Finally, I want to give a few helpful tips to avoid hurdles that once caused me a headache:
- To increase CDN fault tolerance, it is recommended to configure DNS Failover, which helps quickly change the A record in case of server failure. This is done in the DNS records management panel of the domain.
- Websites with a wide geographical reach undoubtedly require a large number of CDN points, but let’s not go overboard. Most likely, users won't notice a significant difference compared to a paid CDN if you place servers in 6-7 locations: Europe, North America (East), North America (West), Singapore, Australia, Hong Kong, or Japan.
- Sometimes hosts do not allow rented servers to be used for CDN purposes. So, if you decide to deploy a content delivery network as a service, don't forget to read the rules of the specific hosting provider beforehand.
- Study , to understand how the continents are connected and take this into account when building the content delivery network.
- Try checking to your servers. This way, you can identify the regions closest to the CDN points and better configure GeoDNS.
- Depending on the tasks, it may also be useful to fine-tune Nginx for specific caching requirements and server load considerations. I found articles about Nginx caching very helpful — and improving performance under high loads: and
Source: habr.com
