如何构建自己的 CDN

2025-05-25

如何构建自己的 CDN

创建您自己的 CDN 网络 - 教程图片来源: pikisuperstar 创建的信息图矢量 — www.freepik.com

内容分发网络 (CDN) 通常被网站和应用程序用来加速静态元素的加载。这是通过将文件缓存在位于世界各地的 CDN 服务器上来实现的。用户通过 CDN 请求数据后,会从最近的服务器接收数据。

所有 CDN 背后的基本原理及其功能大致相同。收到文件请求后,CDN 服务器会从源服务器获取一次文件,然后将其传输给用户,并缓存副本一段时间。后续的数据请求将使用缓存进行处理。所有 CDN 都提供预加载文件、清除缓存、缓存保留时间等选项。

有时,由于各种原因,人们可能需要构建自己的 CDN,因此,我们提供了以下有关如何实现它的指南。

什么时候需要自己的 CDN?

让我们看一下可能需要创建自己的 CDN 的情况:

  • 当你试图省钱时,即使是像BunnyCDN这样经济实惠的解决方案,最终也会花费你每月数百美元
  • 当你想要获得永久缓存或需要保证带宽和资源时
  • 现有 CDN 在您的目标区域没有 PoP
  • 您需要特殊的内容传送设置
  • 您希望通过更靠近用户的方式加快动态内容的交付
  • 您担心第三方 CDN 可能会非法收集和使用用户数据(不符合 GDPR 的服务器)或从事其他非法活动

在大多数其他情况下,使用现有的现成解决方案更为可行。

让我们创建自己的 CDN

即使要构建一个简单的内容交付网络,您也需要以下内容:

  • 域名或子域名
  • 至少两台位于不同地区的服务器。服务器可以是虚拟的,也可以是专用的
  • geoDNS工具。有了它,向域名发送请求的用户将被定向到最近的服务器

注册域名和订购服务器

注册域名很简单——只需在您喜欢的域名区域注册即可。对于 CDN,您还可以使用子域名,例如cdn.domainname.com。以下示例就是这种情况。

在服务器方面,您应该在目标受众所在的地区和国家/地区租用服务器。如果您的项目是跨洲的,那么选择提供全球服务器的托管服务提供商会很方便,例如PQ.hostingDigitalOcean(提供虚拟服务器和云服务器),或OVHLeaseweb(提供专用服务器)。

对于中小型项目,虚拟服务器通常就足够了。它们也比专用服务器便宜得多。例如,PQ.hosting提供25GB NVMe服务器,无限流量,每月仅需4.77 欧元,可在 30 多个地点使用。

让我们在不同的大洲订购三个虚拟服务器。安装时,请选择最新的 Debian。以下是我们的服务器:

  • 法兰克福,IP:199.247.18.199

  • 芝加哥, IP: 149.28.121.123

  • 新加坡, IP: 157.230.240.216

配置 geoDNS

为了确保客户端在向我们的域或子域发送请求时被定向到正确的(最近的)服务器,我们需要一个具有 geoDNS 功能的 DNS 服务器。

geoDNS 的工作原理如下:

  1. 它会获取客户端的 IP(如果客户端发送了 DNS 请求)或用于处理该请求的递归 DNS 服务器的 IP。一般来说,此类递归服务器通常是互联网服务提供商的 DNS。
  2. 通过客户端的 IP 地址识别其所在国家或地区。此操作需要使用 GeoIP 数据库,这类数据库资源非常丰富,甚至还有不错的免费选项
  3. 根据客户端的位置,geoDNS 向其返回最近的 CDN 服务器的 IP 地址。

您可以自行构建具有 geoDNS 功能的 DNS 服务器,但最好使用在世界各地设有服务器且具有开箱即用的Anycast选项的现成解决方案:

  • СlouDNS每月 9.95 美元起,GeoDNS 套餐,默认提供一个 DNS 故障转移
  • Amazon Route 53每月 35 美元起,可处理 5000 万个地理请求。DNS 故障转移功能需单独定价
  • DNS Made Easy每月 125 美元起,提供 10 个 DNS 故障转移
  • Cloudflare,企业包中提供 Geo Steering 功能

订购 geoDNS 时,您需要注意套餐中包含的请求数量,并记住实际请求数量可能远远超出您的预期。任何时候都有数百万个网络爬虫、扫描器、垃圾邮件发送者和其他恶意程序在作祟。

几乎所有 DNS 服务都包含一个对 CDN 构建有用的功能——DNS 故障转移。有了它,您可以配置活动监控,这样如果服务器出现故障,系统就会自动将客户端重定向到正常运行的服务器。

对于我们的 CDN,我们使用ClouDNS及其 GeoDNS 包。

在配置文件中,添加新的 DNS 区域并指定您的域名。如果您使用的是子域名,并且主域名正在使用中,请不要忘记在添加区域后立即添加现有的 DNS 记录。下一步是为 CDN 域名/子域名创建多个 A 记录,每个记录将用于指定的区域。您可以将大洲或国家/地区指定为区域,并且美国和加拿大提供了子区域选项。

在我们的示例中,CDN 将在cdn.sayt.in子域名上运行。添加sayt.in区域后,为该子域名创建第一条 A 记录,并将所有 NA 客户端定向到芝加哥服务器:

添加新的 DNS 记录

对其他区域重复此步骤,不要忘记为默认区域创建一条记录。最终结果如下:

需要 GeoDNS 记录来创建自己的 CDN

最后一条默认记录意味着来自所有未指定地区(欧洲、非洲、卫星互联网用户等)的请求都将被定向到法兰克福服务器。

基本 DNS 配置到此结束。剩下的就是前往注册商网站,将当前的域名服务器替换为 ClouDNS 提供的服务器。在更新过程中,我们会设置服务器。

安装 SSL 证书

我们的 CDN 将使用 HTTPS 运行,因此如果您已经拥有域或子域的 SSL 证书,请将其上传到所有服务器,例如,上传到/etc/ssl/yourdomain/目录。

如果您没有任何证书,可以从 Let's Encrypt 免费获取。ACME Shell 脚本是一个不错的选择。它拥有用户友好的客户端,更重要的是,它允许使用 ClouDNS 的 API 通过 DNS 验证域名/子域名。

我们将仅在一台服务器上安装 acme.sh——欧洲服务器(199.247.18.199),并将证书从该服务器复制到所有其他服务器。要安装它,请运行以下命令:

root@cdn:~# wget -O - https://get.acme.sh | bash; source ~/.bashrc
Enter fullscreen mode Exit fullscreen mode

在安装期间,将创建一个用于自动更新证书的 CRON 任务。

证书颁发后的域名验证将通过 DNS API 进行,因此在 ClouDNS 配置文件的“经销商 API”下,创建一个新的 API 用户并为其指定密码。将生成的 auth-id 和密码输入到以下文件中:~ /.acme.sh/dnsapi/dns_cloudns.sh(不要与 dns_cloudns.sh 混淆。以下是需要取消注释并编辑的行

CLOUDNS_AUTH_ID=<auth-id>
CLOUDNS_AUTH_PASSWORD="<password>"
Enter fullscreen mode Exit fullscreen mode

现在,让我们请求颁发cdn.sayt.in的 SSL 证书

root@cdn:~# acme.sh --issue --dns dns_cloudns -d cdn.sayt.in --reloadcmd "service nginx reload"
Enter fullscreen mode Exit fullscreen mode

为了将来的使用,在参数中,我们留下了一个命令,用于每次更新证书后自动配置重启。

获取证书的过程可能需要两分钟,因此请勿中断。如果出现域验证错误,请尝试重新运行该命令。最后,我们将看到证书的下载位置。

SSL证书颁发

记住这些路径,我们需要在将证书复制到其他服务器时指定它们,并且需要在服务器设置中指定它们。忽略 Nginx 配置重新加载错误——在证书更新期间,在配置完整的服务器上不会发生此错误。

至于 SSL 证书,我们剩下要做的就是将其复制到另外两台服务器,并保存证书路径。在每台服务器上创建相同的目录,然后复制证书文件:

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/
Enter fullscreen mode Exit fullscreen mode

要自动更新证书,您需要在两台服务器上创建每日 CRON 任务。以下是您应该添加到 CRON 作业的命令:

scp -r root@199.247.18.199:/root/.acme.sh/cdn.sayt.in/* /root/.acme.sh/cdn.sayt.in/ && service nginx reload</pre>
Enter fullscreen mode Exit fullscreen mode

请记住,连接到远程源服务器需要密钥访问,无需输入密码。别忘了创建它。

安装和配置Nginx

对于静态内容交付,我们将使用配置为缓存代理服务器的 Nginx。更新软件包列表并将其安装在所有三台服务器上:

root@cdn:~# apt update
root@cdn:~# apt install nginx
Enter fullscreen mode Exit fullscreen mode

不要使用默认配置,而要使用以下配置:

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;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

在配置中,让我们编辑:

  • max_size — 缓存大小不超过可用磁盘空间
  • inactive — 未请求的缓存数据的保留时间
  • ssl_certificatessl_certificate_key — SSL 证书和密钥的路径
  • proxy_cache_valid — 缓存数据的保留时间
  • proxy_pass — CDN 请求缓存数据的源服务器地址。本例中是sayt.in

如你所见,这并非什么高深的科学。考虑到inactiveproxy_cache_valid参数之间的相似性,唯一的难点在于配置保留时间。让我们仔细看看。以下是inactive=7dproxy_cache_valid=90d 时的情况:

  • 如果 7 天内没有重复请求,数据将从缓存中删除
  • 如果在 7 天内重复请求一次,则缓存将在 90 天后被视为过期,并且下一个请求将使 Nginx 从源服务器更新它

处理完nginx.conf,重新加载配置:

root@cdn:~# service nginx reload
Enter fullscreen mode Exit fullscreen mode

所以,我们的 CDN 已经可以使用了!只需每月 15 美元,我们就可以在三大洲获得 PoP 和 3TB 的流量:每个地区 1TB。

检查我们的 CDN

让我们看看从不同位置对 CDN 的 ping 操作。在这种情况下,任何 ping 服务都可以。

Ping 服务器 主持人 知识产权 平均时间,毫秒
德国,柏林 cdn.sayt.in 199.247.18.199 9.6
荷兰,阿姆斯特丹 cdn.sayt.in 199.247.18.199 10.1
法国,巴黎 cdn.sayt.in 199.247.18.199 16.3
英国,伦敦 cdn.sayt.in 199.247.18.199 14.9
加拿大,多伦多 cdn.sayt.in 149.28.121.123 16.2
美国,旧金山 cdn.sayt.in 149.28.121.123 52.7
美国,达拉斯 cdn.sayt.in 149.28.121.123 23.1
美国,芝加哥 cdn.sayt.in 149.28.121.123 2.6
美国,纽约 cdn.sayt.in 149.28.121.123 19.8
新加坡 cdn.sayt.in 157.230.240.216 1.7
日本,东京 cdn.sayt.in 157.230.240.216 74.8
澳大利亚,悉尼 cdn.sayt.in 157.230.240.216 95.9

结果不错。现在,我们在主服务器上放置一张名为test.jpg的测试图片,并检查它通过 CDN 的加载速度。为此,可以使用Ping Admin服务。加载速度应该很快。

让我们制作一个小脚本,以防我们需要清除 CDN 点上的缓存。

清除文件
#!/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
Enter fullscreen mode Exit fullscreen mode

要清除服务器上的所有缓存,只需运行该脚本即可。如果需要清除某个文件,只需指定其路径即可:

root@cdn:~# ./purge.sh /test.jpg 
Enter fullscreen mode Exit fullscreen mode

要清除所有缓存,必须在所有 CDN 服务器上运行脚本。

代替结论

最后,我想给出一些有用的提示,以便您可以避免陷入我已经清除的陷阱:

  • 考虑未来 CDN 的可行性和维护成本。大多数情况下,购买价格低廉的 CDN更高效、更便捷,而且通常更稳定,质量也更好。
  • 为了提高 CDN 的容错能力,建议您设置 DNS 故障转移功能,以便在服务器发生故障时快速切换 A 记录。您可以在 DNS 记录控制面板中进行此操作。
  • 覆盖范围广的网站需要大量的 PoP,但不要过度。如果您在 6-7 个地点(欧洲、北美(东部)、北美(西部)、新加坡、澳大利亚、香港或日本)设有服务器,用户很可能不会注意到您的 CDN 和付费 CDN 之间的区别。
  • 有时,托管服务提供商不允许将租用的服务器用作 CDN。因此,如果您打算创建 CDN 服务,请务必仔细阅读托管服务提供商的条款和条件。
  • 研究海底电缆图以了解各大洲如何连接,并在构建 CDN 时使用这些知识。
  • 尝试从不同位置ping你的服务器。这样,你就能找到距离 PoP 最近的地区,这将有助于你配置 GeoDNS。
文章来源:https://dev.to/megajakob/how-to-build-your-own-cdn-io1
PREV
如何成为更好的学习者
NEXT
如何从文档中删除居高临下的语言