Как стать автором
Обновить

Как сделать и настроить свой CDN

Уровень сложностиСредний
Время на прочтение7 мин
Количество просмотров11K
CDN (сеть доставки контента) представляет собой группу серверов, размещаемых в разных географических регионах с целью обеспечить быструю загрузку контента для пользователей из этих регионов. Чаще всего сети доставки контента используются для ускорения загрузки статических файлов: картинок, видео, скриптов, zip-архивов. Каждый из CDN серверов просто хранит одни и те же файлы, а пользователь получает их с ближайшего сервера.

Хранение контента у большинства сетей доставки контента организовано так: CDN сервер, получив в первый раз от пользователя запрос на отдачу файла, загружает его с оригинального сервера к себе, кэширует и тут же отдает пользователю. Для всех последующих запросов файл уже выдается из кэша. Некоторые сервисы позволяют настраивать длительность хранения кэшируемых данных, а также их предварительную загрузку (прекэш).

Иногда может понадобиться настроить собственную сеть доставки контента. Давайте рассмотрим, для чего это нужно и как это сделать.


Это наша будущая CDN из 5 серверов, которая будет раздавать контент на весь мир

Зачем настраивать собственный CDN


Приведем несколько примеров, когда стоит задуматься о создании своей собственной сети доставки контента:
  • если при использовании даже недорогого CDN вроде этого, расходы на него существенно превышают стоимость создания своего
  • когда хотим иметь гарантированный канал и фиксированное дисковое пространство для постоянного кэша, а не разделять их с другими клиентами
  • если необходимы особые настройки хранения и доставки контента
  • в случае размещения нескольких production-серверов в разных регионах для ускорения доставки динамических данных
  • если не хотим, чтобы сторонние сервисы собирали и хранили данные о наших пользователях, например: IP адрес, запрашиваемые URL, и т.п.
  • когда в нужном нам регионе у других сервисов нет точек присутствия
В большинстве других случаев лучше воспользоваться услугами платного CDN сервиса.

 

Готовимся к запуску


Для реализации задуманного нам понадобится:
  1. Несколько серверов в разных регионах, можно виртуальных (VPS)
  2. Отдельный субдомен. В нашем примере это будет cdn.nashsait.org
  3. geoDNS сервис, с помощью которого пользователь, обращаясь к субдомену, будет направлен на ближайший в его регионе сервер

Арендуем сервера и настраиваем geoDNS


Сперва определимся, где преимущественно находится основная пользовательская аудитория. В нашем примере это Казахстан, поэтому мы определенно должны иметь точку присутствия в этом регионе, чтобы у большинства пользователей всё работало максимально быстро. Остальные сервера будут «разбросаны» по миру. Арендовать их удобнее всего у хостинг-провайдеров, предлагающих сразу несколько локаций для размещения. Пример: PQ.Hosting.

Мы закажем 5 виртуальных серверов стоимостью от ~4€ за каждый и получим 25GB SSD места с безлимитным трафиком. Операционная система — последний Debian или Ubuntu.
Вот наши сервера:

Казахстан, ip: 86.104.73.235

Нидерланды, ip: 94.232.245.17

США, ip: 45.89.53.214

Бразилия, ip: 95.164.5.110

Япония, ip: 5.253.41.115

Чтобы пользователь при обращении к cdn.nashsait.org направлялся на ближайший для него сервер, нам нужен рабочий DNS с функцией geoDNS. Его можно настроить самому или использовать готовый сервис, например СlouDNS.

Мы будем использовать СlouDNS: регистрируемся, выбираем тариф GeoDNS и в личном кабинете добавляем новую DNS-зону, указав наш главный домен nashsait.org. В процессе создания зоны будет предложено выбрать для домена будущие NS-сервера. Отметим все доступные и на будущее скопируем их себе в отдельный текстовый файлик.

Если главный домен уже нами используется (например, на нем размещен сайт или работает электронная почта), то сразу после создания зоны нужно добавить существующие рабочие DNS-записи.

Затем для субдомена cdn.nashsait.org нужно создать несколько A-записей, каждая из которых в зависимости от региона пользователя будет указывать на один из наших CDN серверов. В качестве регионов можно указывать континенты, страны или отдельные штаты (для США и Канады). Начнем с Южной Америки и направим все запросы оттуда на сервер в Бразилии:


Сделаем то же самое для других регионов, при этом один из них рекомендуется добавить как регион «по умолчанию». В итоге список A-записей будет выглядеть так:



Самая нижняя запись «Default» означает, что все остальные, не указанные в других записях регионы (Европа, Африка, спутниковый интернет и т.п.), будут направляться на сервер в Нидерландах.

На этом настройка geoDNS завершена, опционально можно еще включить DNS Failover, он будет мониторить работу серверов и, в случае проблем с каким-то из них, тут же направлять запросы на другой резервный.

Осталось зайти на сайт регистратора нашего домена и изменить NS-сервера для nashsait.org на те, что мы ранее скопировали в отдельный текстовый файл.

 

Добавление SSL сертификатов


Чтобы CDN работал по протоколу HTTPS, мы установим бесплатный SSL сертификат от Let's Encrypt. Это удобно делать с помощью ACME Shell скрипта, который позволяет валидировать домен по DNS через ClouDNS API.

Достаточно установить acme.sh на одном из серверов, а затем скопировать полученный сертификат на все остальные. Выполним установку на сервере в Нидерландах:

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

Стоит заметить, что во время установки создается отдельная CRON задача для автоматического обновления сертификатов в будущем.

При выдаче сертификата проверка домена будет происходить через DNS, а необходимые для этого записи будут автоматически добавлены на ClouDNS через их API. Поэтому в учетной записи на ClouDNS в меню «API&Resellers» нам нужно создать нового API пользователя, придумав для него пароль. Полученный <auth-id> с паролем укажем в файле ~/.acme.sh/dnsapi/dns_cloudns.sh (не перепутайте с похожим dns_clouddns.sh). Вот строки файла, которые нужно раскоментировать и отредактировать:

CLOUDNS_AUTH_ID=<auth-id>
CLOUDNS_AUTH_PASSWORD="<пароль>"

Далее запустим получение SSL сертификата для cdn.nashsait.org

root@cdn:~# acme.sh --issue --dns dns_cloudns -d cdn.nashsait.org --server letsencrypt --reloadcmd "service nginx reload"

Процесс может занимать до нескольких минут и если возникнет ошибка проверки субдомена, попробуйте запустить команду повторно. При успешном результате на экране появится список файлов установленного сертификата:



Запомним эти пути, они будут нужны при копировании сертификата на другие CDN локации и для настройки веб-сервера. Ошибка «Reload error for» не существенна и при дальнейшем обновлении сертификатов на полностью настроенном сервере ее не будет.

Войдем на четыре других сервера и скопируем на каждый полученный сертификат, создав соответствующие директории, чтобы пути к файлам были везде одинаковы:

root@cdn:~# mkdir -p /root/.acme.sh/cdn.nashsait.org_ecc/
root@cdn:~# scp -r root@94.232.245.17:/root/.acme.sh/cdn.nashsait.org_ecc/* /root/.acme.sh/cdn.nashsait.org_ecc/

Это копирование нужно сделать регулярным, поэтому на этих же четырех серверах в CRON добавляем ежедневный запуск команды:
scp -r root@94.232.245.17:/root/.acme.sh/cdn.nashsait.org_ecc/* /root/.acme.sh/cdn.nashsait.org_ecc/ && service nginx reload

Чтобы всё работало, доступ нидерландскому серверу со всех остальных четырех должен быть настроен по ключу, без необходимости ввода пароля. Обязательно сделайте это.

 

Настройка Nginx


На всех пяти CDN точках, в качестве веб-сервера для раздачи контента мы установим Nginx и настроим его как кэширующий proxy-сервер:

root@cdn:~# apt update
root@cdn:~# apt install nginx

Дефолтный файл конфига /etc/nginx/nginx.conf заменим на приведенный ниже:
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=14d;
    proxy_cache_bypass $http_x_update;

server {
  listen 443 ssl;
  server_name cdn.nashsait.org;

  ssl_certificate /root/.acme.sh/cdn.nashsait.org_ecc/fullchain.cer;
  ssl_certificate_key /root/.acme.sh/cdn.nashsait.org_ecc/cdn.nashsait.org.key;

  location / {
    proxy_cache cdn;
    proxy_cache_key $uri$is_args$args;
    proxy_cache_valid 90d;
    proxy_pass https://nashsait.org;
    }
  }
}


В этом конфиге отредактируем:
  • max_size — размер кэша, не больше доступного на диске места
  • inactive — срок хранения кэшированных файлов, к которым не было обращений
  • ssl_certificate и ssl_certificate_key — абсолютные пути к файлам SSL сертификата
  • proxy_cache_valid — срок хранения кэшированных файлов
  • proxy_pass — URL сайта, с которого CDN загружает и кэширует файлы. У нас это nashsait.org
Обратите внимание на схожесть директив inactive и proxy_cache_valid. Чтобы не запутаться, рассмотрим их на простом примере. Вот что происходит при inactive=14d и proxy_cache_valid 90d:
  • если файл не будет запрошен в течение 14 дней, то он удаляется
  • если файл будет запрашиваться хотя бы раз в 14 дней, то он начнет считаться устаревшим только по истечении 90 дней, и после этого срока при очередном запросе Nginx загрузит его по новой с оригинального сервера
Указав нужные значения в nginx.conf, применим их:

root@cdn:~# service nginx reload

Следует отметить, что Nginx не будет кэшировать данные, если они получены с оригинального сервера с какими-либо cookies (заголовок «Set-Cookie»). Игнорировать это условие можно, добавив в конфиг следующие директивы:

proxy_ignore_headers "Set-Cookie";
proxy_hide_header "Set-Cookie";

На этом настройка завершена. Дополнительно можно создать bash-скрипт для очищения кэша:
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


Запуск этого скрипта удалит весь кэш, отдельный файл удаляется так:

root@cdn:~# ./purge.sh /test.jpg

 

Тестируем наш CDN


С помощью онлайн ping-сервисов можно проверить пинги к нашей сети доставки контента из разных мест:
Место запуска Host IP Время, мсек
Германия, Франкфурт cdn.nashsait.org 94.232.245.17 9.6
Испания, Мадрид cdn.nashsait.org 94.232.245.17 37.5
США, Чикаго cdn.nashsait.org 45.89.53.214 16.5
США, Атланта cdn.nashsait.org 45.89.53.214 23.8
Бразилия, Сан-Паулу cdn.nashsait.org 95.164.5.110 1.01
Казахстан, Астана cdn.nashsait.org 86.104.73.235 21.9
Южная Корея, Сеул cdn.nashsait.org 5.253.41.115 31.5
Пинг хороший, теперь разместим в корне основного сайта картинку test.jpg и на сервисе Ping-Admin посмотрим на скорость ее загрузки через CDN:
Место запуска IP Время, сек Скорость загрузки
Бразилия, Сан-Паулу 95.164.5.110 0,233338 12,37 МБ/с
США, Ашберн 45.89.53.214 0,130310 11,24 МБ/с
США, Чикаго 45.89.53.214 0,222213 5,19 МБ/с
Канада, Монреаль 45.89.53.214 0,180502 5,51 МБ/с
Япония, Токио 5.253.41.115 0,091587 43,88 МБ/с
Гонконг 5.253.41.115 0,532564 1,56 МБ/с
Казахстан, Алматы 86.104.73.235 0,195468 4,86 МБ/с
Великобритания, Хэмпшир 94.232.245.17 0,191698 6,57 МБ/с
Нидерланды, Налдвейк 94.232.245.17 0,156096 11,67 МБ/с
Франция, Париж 94.232.245.17 0,301658 4,15 МБ/с
Всё работает, контент раздается быстро. За пару десятков евро в месяц мы получили собственный рабочий CDN с безлимитным трафиком и точками присутствия на всех континентах.
 
Теги:
Хабы:
Всего голосов 27: ↑27 и ↓0+32
Комментарии13

Публикации

Истории

Работа

Ближайшие события